Spaces:
Sleeping
Sleeping
File size: 2,739 Bytes
68f7925 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | import fs from 'fs/promises';
import { NextRequest, NextResponse } from 'next/server';
import path from 'path';
const DATA_ROOT = '/data';
interface FileInfo {
name: string;
type: 'file' | 'directory';
size: number;
lastModified: string;
path: string;
}
export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url);
const relativePath = searchParams.get('path') || '';
// パストラバーサル対策
const normalizedPath = path.normalize(relativePath).replace(/^(\.\.(\/|\\|$))+/, '');
const targetPath = path.join(DATA_ROOT, normalizedPath);
// /data配下であることを確認
if (!targetPath.startsWith(DATA_ROOT)) {
return NextResponse.json({ error: 'Invalid path' }, { status: 400 });
}
try {
// ディレクトリの存在確認
await fs.access(targetPath);
const stat = await fs.stat(targetPath);
if (!stat.isDirectory()) {
return NextResponse.json({ error: 'Path is not a directory' }, { status: 400 });
}
// ディレクトリ内容を取得
const entries = await fs.readdir(targetPath, { withFileTypes: true });
const fileInfos: FileInfo[] = await Promise.all(
entries.map(async (entry) => {
const fullPath = path.join(targetPath, entry.name);
const fileStat = await fs.stat(fullPath);
const relativePath = path.relative(DATA_ROOT, fullPath);
return {
name: entry.name,
type: entry.isDirectory() ? 'directory' : 'file',
size: fileStat.size,
lastModified: fileStat.mtime.toISOString(),
path: `/${relativePath}`,
} as FileInfo;
}),
);
// ディレクトリを先に、その後ファイルを名前順にソート
fileInfos.sort((a, b) => {
if (a.type !== b.type) {
return a.type === 'directory' ? -1 : 1;
}
return a.name.localeCompare(b.name);
});
return NextResponse.json({
path: `/${normalizedPath}`,
items: fileInfos,
});
} catch (error) {
// /dataディレクトリが存在しない場合
if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
return NextResponse.json(
{
path: `/${normalizedPath}`,
items: [],
message: '/dataディレクトリが存在しません(ローカル環境の場合は正常です)',
},
{ status: 200 },
);
}
throw error;
}
} catch (error) {
console.error('[API /admin/data/list] Error:', error);
return NextResponse.json({ error: 'Failed to read directory' }, { status: 500 });
}
}
|