[Feature Bounty] File Manager
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 113
- Forks
- 22
- Avg merge
- 10h 40m
- Merged PRs (30d)
- 13
Description
Modern File Manager API Feature Request
Is your feature request related to a problem?
Users need a modern, performant file management API that can power web interfaces, mobile apps, and automation scripts. The current system requires direct SSH access or WebGUI interaction, making it impossible to build modern file management experiences.
Describe the solution you'd like
Integration of an existing, mature file management service that the Unraid API can host and authenticate, rather than building from scratch. The API should:
-
Full file system operations via API:
- Browse directories with pagination and sorting
- Create, read, update, delete files and folders
- Copy, move, rename with conflict resolution
- Batch operations with progress tracking
- Archive creation/extraction (zip, tar, etc.)
- File permissions management
-
Advanced file features:
- Full-text search across file names and content
- File metadata extraction (EXIF, ID3, etc.)
- Thumbnail generation for images/videos
- File preview for common formats
- Real-time file system monitoring via WebSockets
- File sharing with temporary links
-
Modern UX capabilities:
- Virtual file system for unified view of shares
- Favorites and recent files
- Trash/recycle bin functionality
- File versioning and snapshots
- Clipboard operations (cut/copy/paste)
-
Integration features:
- Direct integration with Docker container volumes
- VM disk image management
- Plugin for VS Code Server or similar IDEs
- WebDAV server for remote access
- S3-compatible API for backup tools
Describe alternatives you've considered
- Krusader Docker container - Requires VNC/noVNC, not API-based
- Midnight Commander - Terminal only, no API
- Direct SMB/NFS access - No unified API, platform-dependent
- FileBrowser - Separate service, not integrated with Unraid API
- Custom scripts - Fragmented, no standard interface
Additional context
Recommended File Management Services
Instead of building from scratch, integrate one of these proven file managers:
Option 1: FileBrowser (Recommended)
# FileBrowser - Modern web file manager with API
- URL: https://github.com/filebrowser/filebrowser
- Language: Go with REST API
- Features:
- Complete file operations (CRUD, copy, move, archive)
- Built-in authentication (can be disabled for SSO)
- Real-time file updates via WebSocket
- Search and filtering
- File sharing with temporary links
- Image thumbnails and previews
- Multiple storage backends
- Extensible via plugins
- Mobile-friendly UI
# Integration approach:
- Run FileBrowser as a subprocess or sidecar
- Proxy API calls through NestJS
- Use shared cookie authentication
- Override auth with Unraid API tokens
Integration Architecture with NestJS
Host the file manager service as a sidecar with shared authentication:
// Integration structure
// Location: api/src/unraid-api/modules/filemanager/
filemanager/
├── filemanager.module.ts # Integration module
├── filemanager.controller.ts # HTTP proxy controller
├── filemanager.service.ts # Service orchestration
├── filemanager.config.ts # Configuration
├── auth/
│ ├── cookie-auth.guard.ts # Shared cookie authentication
│ ├── token-bridge.service.ts # Bridge Unraid tokens to file manager
│ └── sso.strategy.ts # SSO strategy for file manager
├── proxy/
│ ├── api-proxy.middleware.ts # Proxy API calls to file manager
│ ├── websocket-proxy.ts # Proxy WebSocket connections
│ └── response-transformer.ts # Transform responses if needed
└── __tests__/
└── integration.spec.ts
Integration Service Example
// filemanager.service.ts - Orchestrate external file manager
import { Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { spawn, ChildProcess } from 'child_process';
import { createProxyMiddleware } from 'http-proxy-middleware';
import * as cookieParser from 'cookie-parser';
@Injectable()
export class FileManagerService implements OnModuleInit, OnModuleDestroy {
private fileManagerProcess: ChildProcess;
private fileManagerPort: number = 8080;
private fileManagerUrl: string;
constructor(
private readonly configService: ConfigService,
private readonly authService: AuthService,
) {
this.fileManagerUrl = `http://localhost:${this.fileManagerPort}`;
}
async onModuleInit() {
// Start FileBrowser as subprocess
await this.startFileBrowser();
// Wait for service to be ready
await this.waitForService();
// Configure SSO/authentication
await this.configureAuthentication();
}
async onModuleDestroy() {
// Gracefully stop file manager
if (this.fileManagerProcess) {
this.fileManagerProcess.kill('SIGTERM');
}
}
private async startFileBrowser() {
const config = {
port: this.fileManagerPort,
root: '/mnt/user',
database: '/boot/config/plugins/unraid-api/filebrowser.db',
'auth.method': 'proxy', // Use proxy auth headers
'auth.header': 'X-Unraid-User',
};
// Start FileBrowser with configuration
this.fileManagerProcess = spawn('filebrowser', [
'--config', JSON.stringify(config),
'--noauth', // Disable built-in auth, use our proxy
]);
this.fileManagerProcess.stdout.on('data', (data) => {
this.logger.debug(`FileBrowser: ${data}`);
});
this.fileManagerProcess.stderr.on('data', (data) => {
this.logger.error(`FileBrowser Error: ${data}`);
});
}
// Create proxy middleware for API calls
createApiProxy() {
return createProxyMiddleware({
target: this.fileManagerUrl,
changeOrigin: true,
ws: true, // Enable WebSocket proxy
// Add authentication headers
onProxyReq: (proxyReq, req, res) => {
// Extract user from session/cookie
const user = req.user || this.authService.getUserFromCookie(req.cookies);
if (user) {
proxyReq.setHeader('X-Unraid-User', user.username);
proxyReq.setHeader('X-Unraid-Roles', user.roles.join(','));
}
},
// Transform responses if needed
onProxyRes: (proxyRes, req, res) => {
// Add CORS headers if needed
proxyRes.headers['Access-Control-Allow-Credentials'] = 'true';
},
});
}
}
Controller for Proxy
// filemanager.controller.ts
import { Controller, All, Req, Res, UseGuards } from '@nestjs/common';
import { Request, Response } from 'express';
import { CookieAuthGuard } from './auth/cookie-auth.guard';
@Controller('filemanager')
@UseGuards(CookieAuthGuard) // Ensure user is authenticated
export class FileManagerController {
constructor(private readonly fileManagerService: FileManagerService) {}
@All('*')
async proxyRequest(@Req() req: Request, @Res() res: Response) {
// Proxy all requests to file manager service
const proxy = this.fileManagerService.createApiProxy();
proxy(req, res, (err) => {
if (err) {
res.status(500).json({ error: 'Proxy error', details: err.message });
}
});
}
}
Configuration
Create a separate configuration file following the existing pattern:
// Location: api/dev/configs/filemanager.json
// This follows the same pattern as connect.json, cloud.json, etc.
{
"service": "filebrowser", // Which file manager to use
"port": 8080, // Port for the file manager service
"binary": "/usr/local/emhttp/plugins/unraid-api/filemanager/filebrowser",
"database": "/boot/config/plugins/unraid-api/filebrowser.db",
"auth": {
"method": "proxy", // Use proxy authentication
"header": "X-Unraid-User"
},
"roots": [
{
"name": "User Shares",
"path": "/mnt/user",
"writable": true
},
{
"name": "Cache",
"path": "/mnt/cache",
"writable": true
},
{
"name": "Disks",
"path": "/mnt/disk*",
"writable": true
},
{
"name": "Boot",
"path": "/boot",
"writable": false
}
]
}
// Environment variable configuration
// Location: .env or environment
FILEMANAGER_ENABLED=true
FILEMANAGER_SERVICE=filebrowser
FILEMANAGER_PORT=8080
Environment (if relevant)
Unraid OS Version: 6.11+ (any version with API support)
Pre-submission Checklist
- I have searched existing issues to ensure this feature hasn't already been requested
- This is not an Unraid Connect related feature
- I have provided clear examples and implementation details for the feature
Bounty Development Guidelines
For developers interested in implementing this feature:
- DO NOT build a file manager from scratch - Use FileBrowser, Filestash, or similar
- Run file manager as a sidecar service - Start/stop with NestJS lifecycle
- Implement authentication bridge - Share cookies between Unraid API and file manager
- Use HTTP proxy pattern - Proxy all requests through NestJS for auth/control
- Bundle the file manager binary - Download during build-txz.ts like other tools
- Create WebGUI page - Follow LogViewer.vue pattern for iframe integration
- Add to Tools menu - Include navigation entry with proper permissions
- Start with FileBrowser - Most mature option with best API
- Disable file manager's built-in auth - Use Unraid API authentication only
- Proxy WebSocket connections - Ensure real-time updates work
- Map Unraid paths correctly - /mnt/user, /mnt/disk*, /mnt/cache
- Test permission inheritance - Ensure Unraid permissions are respected
- Style iframe properly - Full height, no borders, responsive layout
- Document the integration - How to configure, extend, and troubleshoot
Integration Strategy
The implementation should:
For FileBrowser Integration:
- Download FileBrowser binary during plugin build
- Start as subprocess with
--noauthflag - Use proxy auth headers (X-Unraid-User, X-Unraid-Roles)
- Proxy all
/filemanager/*routes through NestJS - Store database in
/boot/config/plugins/unraid-api/
For Authentication:
- Use existing Unraid API session cookies
- Bridge authentication to file manager via headers
- Implement cookie-auth.guard.ts for validation
- Map Unraid roles to file manager permissions
Performance Considerations
- Use streams for large file operations
- Implement request debouncing for file system watchers
- Cache directory listings with TTL
- Use worker threads for CPU-intensive operations (thumbnails, indexing)
- Implement progressive loading for large directories
- Use database for search index if dealing with millions of files
Security Requirements
- Path validation: Prevent directory traversal attacks
- Permission checking: Respect Unraid user permissions
- Rate limiting: Prevent DoS through excessive operations
- File type validation: Prevent execution of malicious files
- Sandboxing: Isolate file operations from system
- Audit logging: Track all file operations
Testing Requirements
- Unit tests for all services
- Integration tests for GraphQL operations
- Performance tests with large directories (10,000+ files)
- Security tests for path traversal and permission bypass
- Compatibility tests with different file systems (XFS, BTRFS, ZFS)
- Stress tests for concurrent operations
WebGUI Integration
Create a WebGUI page for the file browser following the existing log viewer pattern:
// Location: web/pages/FileManager.vue
// Follow the pattern from web/pages/LogViewer.vue
<template>
<PageLayout :title="t('file_manager.title')" contentClass="!p-0">
<iframe
ref="fileManagerFrame"
:src="fileManagerUrl"
class="w-full h-full border-0"
@load="onFrameLoad"
/>
</PageLayout>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue';
import { useApiStore } from '@/stores/api';
const apiStore = useApiStore();
// Use the proxied file manager URL
const fileManagerUrl = computed(() => {
const baseUrl = apiStore.baseUrl || '';
return `${baseUrl}/filemanager`;
});
const fileManagerFrame = ref<HTMLIFrameElement>();
const onFrameLoad = () => {
// Pass authentication token to iframe if needed
if (fileManagerFrame.value?.contentWindow) {
// The proxy should handle auth, but we can pass additional data if needed
fileManagerFrame.value.contentWindow.postMessage({
type: 'auth',
token: apiStore.token,
}, '*');
}
};
</script>
Add navigation entry:
// Location: web/composables/use-navigation.ts
// Add to the Tools section
{
label: 'File Manager',
icon: 'folder-open',
to: '/file-manager',
permission: 'share.read',
}
Deliverables
- FileManager integration module for NestJS
- Authentication bridge implementation
- HTTP/WebSocket proxy configuration
- FileBrowser binary download in build-txz.ts
- Service lifecycle management (start/stop)
- Configuration for Unraid paths
- WebGUI page (FileManager.vue) following LogViewer pattern
- Navigation integration in Tools menu
- Documentation for integration and usage
- Tests for auth bridge and proxy
- Example nginx configuration for production
Why Not Build From Scratch?
Building a file manager is a massive undertaking that requires:
- Handling edge cases for thousands of file system scenarios
- Security hardening against path traversal, symlink attacks, etc.
- Performance optimization for large directories
- Cross-platform compatibility issues
- Extensive testing across file systems
FileBrowser alone has:
- 7+ years of development
- 20,000+ GitHub stars
- 100+ contributors
- Battle-tested in production
By integrating an existing solution:
- We get a mature, feature-complete file manager immediately
- Security updates and bug fixes from the upstream project
- Community plugins and extensions
- Well-documented API
- Active development and support
The integration approach gives us:
- Full control over authentication and authorization
- Ability to customize the UI through the file manager's theming
- Easy upgrades by updating the binary
- Fallback to direct file manager access if needed
- Lower maintenance burden for the Unraid API team
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading the existing LogViewer.vue pattern and the configuration conventions in api/dev/configs, then inspect the proposed api/src/unraid-api/modules/filemanager/ entry points. Scope the FileBrowser sidecar, authentication bridge, proxy routes, WebGUI page, and build packaging before implementing. Done requires documented integration, permission and path-safety coverage, and the listed unit and integration tests.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go, typescript
- Domain
- backend-api-design, devops, security, web-dev
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100