mirror of
https://github.com/StarFleetCPTN/GoMFT.git
synced 2026-09-08 15:41:20 +02:00
Add audit logging to storage providers
This commit is contained in:
@@ -58,12 +58,6 @@ GoMFT is a web-based managed file transfer application built with Go, leveraging
|
|||||||
- Wasabi
|
- Wasabi
|
||||||
- Local filesystem
|
- Local filesystem
|
||||||
- And more via rclone
|
- And more via rclone
|
||||||
- **Webhook Notifications**: Receive real-time notifications of job events:
|
|
||||||
- Configurable webhook URLs
|
|
||||||
- HMAC-SHA256 authentication with secrets
|
|
||||||
- Custom HTTP headers
|
|
||||||
- Selectable events (job success, job failure)
|
|
||||||
- Detailed JSON payload with job information
|
|
||||||
- **Multiple Notification Services**: Get job status updates through various notification channels:
|
- **Multiple Notification Services**: Get job status updates through various notification channels:
|
||||||
- Email notifications with configurable SMTP settings
|
- Email notifications with configurable SMTP settings
|
||||||
- Webhooks with authentication for custom integrations
|
- Webhooks with authentication for custom integrations
|
||||||
@@ -135,9 +129,15 @@ cd gomft
|
|||||||
2. Install dependencies:
|
2. Install dependencies:
|
||||||
```bash
|
```bash
|
||||||
go mod download
|
go mod download
|
||||||
|
go install github.com/a-h/templ/cmd/templ@latest
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Build the application:
|
3. Generate template code:
|
||||||
|
```bash
|
||||||
|
templ generate
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Build the application:
|
||||||
```bash
|
```bash
|
||||||
go build -o gomft
|
go build -o gomft
|
||||||
```
|
```
|
||||||
@@ -230,6 +230,7 @@ services:
|
|||||||
- GOOGLE_CLIENT_ID=your_google_client_id
|
- GOOGLE_CLIENT_ID=your_google_client_id
|
||||||
- GOOGLE_CLIENT_SECRET=your_google_client_secret
|
- GOOGLE_CLIENT_SECRET=your_google_client_secret
|
||||||
- TOTP_ENCRYPTION_KEY=your_32_byte_encryption_key_here
|
- TOTP_ENCRYPTION_KEY=your_32_byte_encryption_key_here
|
||||||
|
- GOMFT_ENCRYPTION_KEY=your_32_byte_encryption_key_here
|
||||||
- EMAIL_ENABLED=true
|
- EMAIL_ENABLED=true
|
||||||
- EMAIL_HOST=smtp.example.com
|
- EMAIL_HOST=smtp.example.com
|
||||||
- EMAIL_PORT=587
|
- EMAIL_PORT=587
|
||||||
@@ -255,539 +256,14 @@ docker-compose up -d
|
|||||||
|
|
||||||
For more information and available tags, visit the [GoMFT Docker Hub page](https://hub.docker.com/r/starfleetcptn/gomft).
|
For more information and available tags, visit the [GoMFT Docker Hub page](https://hub.docker.com/r/starfleetcptn/gomft).
|
||||||
|
|
||||||
---
|
Full documentation is available at [https://starfleetcptn.github.io/GoMFT/](https://starfleetcptn.github.io/GoMFT/).
|
||||||
|
|
||||||
## Configuration
|
## License
|
||||||
|
|
||||||
GoMFT uses an environment file located at `.env` in the root directory of the application. On first run, a default configuration will be created:
|
[MIT License](LICENSE) - see the full license terms
|
||||||
|
|
||||||
```ini
|
The GoMFT logo is licensed under the Creative Commons Attribution 4.0 International Public License.
|
||||||
# Basic configuration
|
|
||||||
SERVER_ADDRESS=:8080
|
|
||||||
DATA_DIR=/app/data
|
|
||||||
BACKUP_DIR=/app/backups
|
|
||||||
JWT_SECRET=change_this_to_a_secure_random_string
|
|
||||||
BASE_URL=http://localhost:8080
|
|
||||||
|
|
||||||
# Google OAuth configuration (optional, for built-in authentication)
|
The gopher design is from https://github.com/egonelbre/gophers.
|
||||||
GOOGLE_CLIENT_ID=your_google_client_id
|
|
||||||
GOOGLE_CLIENT_SECRET=your_google_client_secret
|
|
||||||
|
|
||||||
# Email configuration
|
The original Go gopher was designed by Renee French (http://reneefrench.blogspot.com/).
|
||||||
EMAIL_ENABLED=true
|
|
||||||
EMAIL_HOST=smtp.example.com
|
|
||||||
EMAIL_PORT=587
|
|
||||||
EMAIL_FROM_EMAIL=gomft@example.com
|
|
||||||
EMAIL_FROM_NAME=GoMFT
|
|
||||||
EMAIL_REPLY_TO=
|
|
||||||
EMAIL_ENABLE_TLS=true
|
|
||||||
EMAIL_REQUIRE_AUTH=true
|
|
||||||
EMAIL_USERNAME=smtp_username
|
|
||||||
EMAIL_PASSWORD=smtp_password
|
|
||||||
|
|
||||||
# Two-Factor Authentication configuration
|
|
||||||
TOTP_ENCRYPTION_KEY=your_32_byte_encryption_key_here
|
|
||||||
|
|
||||||
# UserID and GroupID
|
|
||||||
PUID=1000
|
|
||||||
PGID=1000
|
|
||||||
```
|
|
||||||
|
|
||||||
### Configuration Options
|
|
||||||
|
|
||||||
- `SERVER_ADDRESS`: The address and port to run the server on
|
|
||||||
- `DATA_DIR`: Directory for storing application data (database and configs)
|
|
||||||
- `BACKUP_DIR`: Directory for storing database backups
|
|
||||||
- `JWT_SECRET`: Secret key for JWT token generation
|
|
||||||
- `BASE_URL`: Base URL for generating links in emails (e.g., password reset links)
|
|
||||||
- Google OAuth configuration for built-in authentication:
|
|
||||||
- `GOOGLE_CLIENT_ID`: Your Google OAuth client ID
|
|
||||||
- `GOOGLE_CLIENT_SECRET`: Your Google OAuth client secret
|
|
||||||
- Email configuration settings for system notifications and password resets:
|
|
||||||
- `EMAIL_ENABLED`: Set to `true` to enable email functionality
|
|
||||||
- `EMAIL_HOST`: SMTP server hostname
|
|
||||||
- `EMAIL_PORT`: SMTP server port (usually 587 for TLS, 465 for SSL, or 25 for non-secure)
|
|
||||||
- `EMAIL_USERNAME`: Username for SMTP authentication
|
|
||||||
- `EMAIL_PASSWORD`: Password for SMTP authentication
|
|
||||||
- `EMAIL_FROM_EMAIL`: Email address used as sender
|
|
||||||
- `EMAIL_FROM_NAME`: Name displayed as the sender
|
|
||||||
- `EMAIL_REPLY_TO`: Optional reply-to email address
|
|
||||||
- `EMAIL_ENABLE_TLS`: Set to `true` to use TLS for secure email transmission
|
|
||||||
- `EMAIL_REQUIRE_AUTH`: Set to `true` to require authentication for SMTP connections, or `false` for servers that don't need authentication
|
|
||||||
|
|
||||||
- Two-Factor Authentication (2FA) configuration:
|
|
||||||
- `TOTP_ENCRYPTION_KEY`: Secret key used to encrypt/decrypt TOTP secrets (for 2FA)
|
|
||||||
- Should be exactly 32 bytes (characters) for optimal security
|
|
||||||
- If not set, a default development key will be used (not secure for production)
|
|
||||||
- If shorter than 32 bytes, it will be automatically padded (less secure)
|
|
||||||
- If longer than 32 bytes, it will be truncated to 32 bytes
|
|
||||||
- Example: `TOTP_ENCRYPTION_KEY=abcdefghijklmnopqrstuvwxyz123456`
|
|
||||||
|
|
||||||
|
|
||||||
- SSL/TLS Verification Control:
|
|
||||||
- `SKIP_SSL_VERIFY`: Set to `true` to disable SSL/TLS certificate verification for outgoing connections (e.g., webhooks, email). Use with caution, as this can expose connections to man-in-the-middle attacks. Defaults to `false` (verification enabled).
|
|
||||||
- Example: `SKIP_SSL_VERIFY=true`
|
|
||||||
### Logging Configuration
|
|
||||||
|
|
||||||
GoMFT provides configurable logging with rotation support through the following environment variables:
|
|
||||||
|
|
||||||
- `LOGS_DIR`: Directory where log files are stored (default: `./data/logs`)
|
|
||||||
- `LOG_MAX_SIZE`: Maximum size in megabytes for each log file before rotation (default: `10`)
|
|
||||||
- `LOG_MAX_BACKUPS`: Number of old log files to retain (default: `5`)
|
|
||||||
- `LOG_MAX_AGE`: Maximum number of days to retain old log files (default: `30`)
|
|
||||||
- `LOG_COMPRESS`: Whether to compress rotated log files (default: `true`)
|
|
||||||
- `LOG_LEVEL`: Controls verbosity level of logging (values: `error`, `info`, `debug`, default: `info`)
|
|
||||||
- `error`: Only show errors and critical issues
|
|
||||||
- `info`: Show errors and general operational information (default)
|
|
||||||
- `debug`: Show all messages including detailed debugging information
|
|
||||||
|
|
||||||
Log files contain detailed information about file transfers, job execution, and system operations, which can be useful for troubleshooting and auditing.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
1. Start the server:
|
|
||||||
```bash
|
|
||||||
./gomft
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Access the web interface at `http://localhost:8080`
|
|
||||||
|
|
||||||
3. Log in with the default admin account:
|
|
||||||
- Email: `admin@example.com`
|
|
||||||
- Password: `admin`
|
|
||||||
- **Important**: Change this password immediately after first login
|
|
||||||
|
|
||||||
4. Create transfer configurations:
|
|
||||||
- Navigate to "Transfer Configs" section
|
|
||||||
- Configure source and destination locations with connection details
|
|
||||||
- Set file patterns and archive options as needed
|
|
||||||
- Configure performance settings:
|
|
||||||
- Set "Concurrent Transfers" slider to optimize throughput
|
|
||||||
- Use higher values (8-16) for many small files or fast networks
|
|
||||||
- Use lower values (1-4) for large files or limited bandwidth
|
|
||||||
- Consider source/destination system capabilities when setting
|
|
||||||
|
|
||||||
5. Create jobs using your configurations:
|
|
||||||
- Navigate to "Jobs" section
|
|
||||||
- Select an existing transfer config
|
|
||||||
- Use the visual schedule builder to set your timing preferences:
|
|
||||||
- Choose from common presets (hourly, daily, weekly, monthly)
|
|
||||||
- Customize with specific days, times, or intervals
|
|
||||||
- See a plain-language description of your schedule
|
|
||||||
- View upcoming run times on the interactive calendar
|
|
||||||
- Switch to advanced mode for direct cron expression input if needed
|
|
||||||
- Enable/disable jobs with a single click
|
|
||||||
|
|
||||||
6. Monitor transfers:
|
|
||||||
- View active and completed transfers on the Dashboard
|
|
||||||
- Check detailed transfer history with performance metrics
|
|
||||||
- View job run details including any error messages
|
|
||||||
|
|
||||||
7. Configure webhook notifications:
|
|
||||||
- Enable webhooks in job settings to receive notifications
|
|
||||||
- Provide a valid webhook URL where notifications will be sent
|
|
||||||
- Optionally set a webhook secret for HMAC-SHA256 signature verification
|
|
||||||
- Configure custom HTTP headers in JSON format if needed
|
|
||||||
- Choose notification triggers (job success, job failure, or both)
|
|
||||||
- Test your webhook integration with manual job runs
|
|
||||||
|
|
||||||
8. **Webhook Notifications**:
|
|
||||||
- **Webhook Integration**: Send notifications to external systems when jobs complete
|
|
||||||
- **Secure Authentication**: HMAC-SHA256 signature for webhook verification
|
|
||||||
- **Custom Headers**: Add custom HTTP headers to webhook requests
|
|
||||||
- **Flexible Configuration**: Configure different webhooks for different jobs
|
|
||||||
- **Event Selection**: Choose to send notifications on success, failure, or both
|
|
||||||
- **Detailed Payload**: Rich JSON payload with complete job execution details
|
|
||||||
|
|
||||||
9. **Multiple Notification Services**:
|
|
||||||
- **Pushbullet Integration**: Send notifications to your devices through Pushbullet
|
|
||||||
- Device targeting support for specific device delivery
|
|
||||||
- Customizable title and message templates
|
|
||||||
- API key-based authentication
|
|
||||||
- **Ntfy Integration**: Use public ntfy.sh or self-hosted ntfy server
|
|
||||||
- Topic-based routing of notifications
|
|
||||||
- Priority levels for different job events
|
|
||||||
- Optional username/password authentication for private servers
|
|
||||||
- Customizable title and message templates
|
|
||||||
- **Gotify Integration**: Send notifications to self-hosted Gotify servers
|
|
||||||
- Application token-based authentication
|
|
||||||
- Priority levels (1-10) for different notification importance
|
|
||||||
- Customizable title and message templates
|
|
||||||
- **Pushover Integration**: Professional notification delivery service
|
|
||||||
- Application and user key authentication
|
|
||||||
- Device targeting for selective delivery
|
|
||||||
- Sound selection for different notification types
|
|
||||||
- Priority levels from lowest to emergency
|
|
||||||
- Customizable title and message templates
|
|
||||||
- **Common Features**:
|
|
||||||
- Variable substitution in notification templates
|
|
||||||
- Job data access in templates (status, files, bytes, times)
|
|
||||||
- Event-based filtering (job start, completion, errors)
|
|
||||||
- Success/failure tracking for diagnostic purposes
|
|
||||||
|
|
||||||
10. Manage file metadata:
|
|
||||||
- Navigate to the "Files" section to view all processed files
|
|
||||||
- Use filters to quickly find files by status, job ID, or filename
|
|
||||||
- Click on any file to view detailed metadata including timestamps, size, and hash
|
|
||||||
- Use the advanced search page for complex queries with multiple criteria
|
|
||||||
- Delete file metadata records when no longer needed
|
|
||||||
- View files associated with specific jobs by navigating from the job details
|
|
||||||
|
|
||||||
11. Utilize admin tools (administrators only):
|
|
||||||
- Access the "Admin Tools" section from the navigation menu
|
|
||||||
- View system statistics and server information
|
|
||||||
- Create and manage database backups
|
|
||||||
- Browse and download system log files with the integrated log viewer
|
|
||||||
- Perform database maintenance and optimization tasks
|
|
||||||
- View webhook documentation and integration details
|
|
||||||
|
|
||||||
### User Management
|
|
||||||
|
|
||||||
GoMFT uses a role-based access control system with flexible authentication options:
|
|
||||||
|
|
||||||
- **Administrators**: Can create and manage users, access all features
|
|
||||||
- **Regular Users**: Can manage transfers and view history
|
|
||||||
|
|
||||||
#### Authentication Options
|
|
||||||
|
|
||||||
1. **Built-in Authentication**:
|
|
||||||
- Email/password login with secure password hashing
|
|
||||||
- JWT-based session management
|
|
||||||
- Password history tracking
|
|
||||||
- Account lockout protection
|
|
||||||
- Self-service password reset
|
|
||||||
|
|
||||||
2. **External Authentication Providers**:
|
|
||||||
- **Authentik Integration**:
|
|
||||||
- Enterprise-grade SSO capabilities
|
|
||||||
- Automatic user provisioning
|
|
||||||
- Role synchronization
|
|
||||||
- Group mapping support
|
|
||||||
- Secure token exchange
|
|
||||||
|
|
||||||
- **OpenID Connect (OIDC)**:
|
|
||||||
- Standard-compliant identity provider support
|
|
||||||
- Automatic user creation and updates
|
|
||||||
- Role mapping from OIDC claims
|
|
||||||
- Multiple provider support
|
|
||||||
- Secure token validation
|
|
||||||
|
|
||||||
- **OAuth2 Providers**:
|
|
||||||
- Google authentication
|
|
||||||
- GitHub integration
|
|
||||||
- Other OAuth2-compliant providers
|
|
||||||
- Custom provider configuration
|
|
||||||
- Automatic profile synchronization
|
|
||||||
|
|
||||||
3. **Security Features**:
|
|
||||||
- Secure password hashing with bcrypt
|
|
||||||
- JWT-based authentication with tokens
|
|
||||||
- Password history tracking prevents reuse
|
|
||||||
- Account lockout after failed attempts
|
|
||||||
- Two-factor authentication support
|
|
||||||
- Session management and timeout
|
|
||||||
- Secure token storage and handling
|
|
||||||
|
|
||||||
4. **User Profile Management**:
|
|
||||||
- Theme preferences (light/dark mode)
|
|
||||||
- Profile information updates
|
|
||||||
- Password change functionality
|
|
||||||
- Two-factor authentication setup
|
|
||||||
- External account linking
|
|
||||||
|
|
||||||
### Two-Factor Authentication (2FA) Implementation
|
|
||||||
|
|
||||||
#### Overview
|
|
||||||
This implementation adds TOTP-based (Time-based One-Time Password) two-factor authentication support to the application, compatible with standard authenticator apps like Google Authenticator, Authy, and others.
|
|
||||||
|
|
||||||
#### Features
|
|
||||||
- TOTP-based authentication (RFC 6238 compliant)
|
|
||||||
- QR code setup for easy enrollment
|
|
||||||
- Backup codes for account recovery
|
|
||||||
- Rate-limited verification attempts
|
|
||||||
- Secure secret storage
|
|
||||||
|
|
||||||
#### Database Changes
|
|
||||||
The following fields have been added to the `users` table:
|
|
||||||
- `two_factor_secret`: Stores the TOTP secret key
|
|
||||||
- `two_factor_enabled`: Boolean flag indicating if 2FA is enabled
|
|
||||||
- `backup_codes`: Stores recovery backup codes
|
|
||||||
|
|
||||||
#### Setup Process
|
|
||||||
1. Navigate to `/profile/2fa/setup`
|
|
||||||
2. Scan the displayed QR code with your authenticator app
|
|
||||||
3. Enter the verification code to confirm setup
|
|
||||||
4. Save your backup codes in a secure location
|
|
||||||
|
|
||||||
#### Login Flow
|
|
||||||
1. Enter email and password as usual
|
|
||||||
2. If 2FA is enabled:
|
|
||||||
- Enter the 6-digit code from your authenticator app
|
|
||||||
- Alternatively, use a backup code if you can't access your authenticator
|
|
||||||
|
|
||||||
#### Security Considerations
|
|
||||||
- The TOTP secrets are encrypted using AES-256-GCM
|
|
||||||
- You must set the `TOTP_ENCRYPTION_KEY` environment variable in production
|
|
||||||
- This key should be 32 bytes (characters) long and kept confidential
|
|
||||||
- Changing this key after users have set up 2FA will invalidate their existing 2FA configurations
|
|
||||||
- For high-security deployments, store this key in a secure vault and inject it at runtime
|
|
||||||
|
|
||||||
### Transfer Configuration Options
|
|
||||||
|
|
||||||
1. **Source/Destination Types**:
|
|
||||||
- Google Drive
|
|
||||||
- Google Photos
|
|
||||||
- Local filesystem
|
|
||||||
- Amazon S3
|
|
||||||
- MinIO (S3-compatible storage)
|
|
||||||
- NextCloud
|
|
||||||
- Backblaze B2
|
|
||||||
- Wasabi
|
|
||||||
- Hetzner Storage Box
|
|
||||||
- SFTP
|
|
||||||
- FTP
|
|
||||||
- SMB/CIFS shares
|
|
||||||
- And many more via rclone
|
|
||||||
|
|
||||||
2. **Connection Options**:
|
|
||||||
- Host/server addresses
|
|
||||||
- Authentication (username/password or key files)
|
|
||||||
- OAuth2 authentication for Google services
|
|
||||||
- Port configurations
|
|
||||||
- Cloud credentials (access keys, secret keys)
|
|
||||||
- Bucket and region settings
|
|
||||||
- Custom endpoints
|
|
||||||
- Custom rclone flags
|
|
||||||
|
|
||||||
3. **Google Photos Specific Options**:
|
|
||||||
- Read-only mode for safer operations
|
|
||||||
- Start year filter for historical photos
|
|
||||||
- Include/exclude archived media
|
|
||||||
- Album path configuration
|
|
||||||
- Built-in or custom OAuth authentication
|
|
||||||
|
|
||||||
4. **Google Drive Specific Options**:
|
|
||||||
- Folder ID for specific directory access
|
|
||||||
- Team/Shared Drive ID support
|
|
||||||
- Built-in or custom OAuth authentication
|
|
||||||
- Path-based navigation
|
|
||||||
|
|
||||||
5. **File Options**:
|
|
||||||
- File patterns for filtering (e.g., `*.txt`, `data_*.csv`)
|
|
||||||
- Output patterns for dynamic naming
|
|
||||||
- Archive options for transferred files
|
|
||||||
- Skip already processed files to avoid duplicates
|
|
||||||
- Concurrent file transfers (configurable per job)
|
|
||||||
|
|
||||||
6. **Performance Options**:
|
|
||||||
- **Multi-threaded File Transfers**: Process multiple files simultaneously for higher throughput
|
|
||||||
- Configurable concurrency level (1-32 concurrent transfers)
|
|
||||||
- Per-job concurrency settings to optimize for different storage types
|
|
||||||
- Automatic transfer queue management to prevent overloading systems
|
|
||||||
- Adaptive processing based on source/destination capabilities
|
|
||||||
|
|
||||||
7. **Schedule Options**:
|
|
||||||
- **Visual Schedule Builder**: Intuitive interface for setting schedule preferences
|
|
||||||
- **Natural Language Description**: Plain-language description of schedule
|
|
||||||
- **Interactive Calendar**: Visual representation of upcoming runs
|
|
||||||
- **Common Presets**: Hourly, daily, weekly, monthly schedules
|
|
||||||
- **Advanced Mode**: Manual cron expression input for complex schedules
|
|
||||||
- **Schedule Validation**: Preview and confirm schedule
|
|
||||||
- **Enable/Disable**: One-click enable/disable
|
|
||||||
- **Time Zone Support**: Accurate scheduling based on user's time zone
|
|
||||||
|
|
||||||
8. **Notification Options**:
|
|
||||||
- **Email Notifications**: Receive job status updates via email
|
|
||||||
- **Webhook Notifications**: Integration with external systems
|
|
||||||
- **Pushbullet**: Push notifications to your devices
|
|
||||||
- **Ntfy**: Simple push notifications via ntfy.sh
|
|
||||||
- **Gotify**: Self-hosted notification server integration
|
|
||||||
- **Pushover**: Professional notification service
|
|
||||||
- Configure event triggers (start, complete, error)
|
|
||||||
- Customize notification message templates
|
|
||||||
- Selective notification based on job status
|
|
||||||
|
|
||||||
### Email Notifications
|
|
||||||
|
|
||||||
GoMFT supports email notifications for various features:
|
|
||||||
|
|
||||||
- **Password Reset**: Users can request password reset links sent to their registered email
|
|
||||||
- **Styled Emails**: Professional HTML emails that match the application's design theme
|
|
||||||
- **Secure Tokens**: One-time use secure tokens with 15-minute expiration for enhanced security
|
|
||||||
- **Flexible Configuration**: Easily configure your SMTP server settings
|
|
||||||
- **Authentication Options**: Support for both authenticated and unauthenticated SMTP servers
|
|
||||||
- **TLS Support**: Secure communication with your SMTP server
|
|
||||||
- **Development Mode**: When emails are disabled, reset links are logged to the console
|
|
||||||
|
|
||||||
To configure email functionality:
|
|
||||||
|
|
||||||
1. Edit the `.env` file and provide your SMTP server details
|
|
||||||
2. Set `EMAIL_ENABLED=true` in the email configuration section
|
|
||||||
3. Ensure the `BASE_URL` setting is configured correctly for your deployment
|
|
||||||
|
|
||||||
### Webhook Integration
|
|
||||||
|
|
||||||
GoMFT can send webhook notifications to external systems when jobs complete. This allows integration with monitoring tools, chat applications, custom notification systems, or workflow automation platforms.
|
|
||||||
|
|
||||||
#### Webhook Payload Structure
|
|
||||||
|
|
||||||
Webhook notifications are sent as HTTP POST requests with a JSON payload containing detailed information about the job execution:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"event_type": "job_execution",
|
|
||||||
"job_id": 123,
|
|
||||||
"job_name": "Daily Backup",
|
|
||||||
"config_id": 456,
|
|
||||||
"config_name": "S3 to Local Backup",
|
|
||||||
"status": "completed",
|
|
||||||
"start_time": "2023-07-14T15:30:00Z",
|
|
||||||
"end_time": "2023-07-14T15:35:42Z",
|
|
||||||
"duration_seconds": 342,
|
|
||||||
"bytes_transferred": 1048576,
|
|
||||||
"files_transferred": 25,
|
|
||||||
"history_id": 789,
|
|
||||||
"source": {
|
|
||||||
"type": "s3",
|
|
||||||
"path": "my-bucket/data"
|
|
||||||
},
|
|
||||||
"destination": {
|
|
||||||
"type": "local",
|
|
||||||
"path": "/backups/data"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
For failed transfers, additional error information is included:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"status": "failed",
|
|
||||||
"error_message": "Permission denied accessing destination path"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Webhook Authentication
|
|
||||||
|
|
||||||
When a webhook secret is configured, GoMFT signs the payload using HMAC-SHA256 and includes the signature in the `X-Hub-Signature-256` header. To verify the webhook:
|
|
||||||
|
|
||||||
1. Compute the HMAC-SHA256 of the raw request body using your shared secret
|
|
||||||
2. Compare it with the value in the `X-Hub-Signature-256` header
|
|
||||||
3. Process the webhook only if the signatures match
|
|
||||||
|
|
||||||
This ensures that webhook requests are authentic and haven't been tampered with.
|
|
||||||
|
|
||||||
### Admin Tools
|
|
||||||
|
|
||||||
GoMFT provides a comprehensive set of administrative tools for system management and monitoring:
|
|
||||||
|
|
||||||
#### Log Viewer
|
|
||||||
|
|
||||||
The Admin Tools panel includes an integrated log viewer with the following features:
|
|
||||||
|
|
||||||
- **Log File Browser**: View a list of all available log files in the system
|
|
||||||
- **Real-time Log Viewing**: View log file contents directly in the web interface
|
|
||||||
- **Refresh Function**: Update the log list and content with the latest information
|
|
||||||
- **User-friendly Interface**: Clean, readable presentation with custom scrolling
|
|
||||||
- **Dark Mode Support**: Consistent theming with the rest of the application
|
|
||||||
- **Navigation**: Easily switch between different log files
|
|
||||||
|
|
||||||
This log viewer allows administrators to:
|
|
||||||
- Monitor system activity and diagnose issues without requiring server access
|
|
||||||
- View application logs, scheduler logs, and transfer logs in one place
|
|
||||||
- Track down errors and warning messages in real-time
|
|
||||||
|
|
||||||
#### Database Management
|
|
||||||
|
|
||||||
The Admin Tools interface also includes database management capabilities:
|
|
||||||
- Create and manage database backups
|
|
||||||
- Restore from previous backups
|
|
||||||
- Download backups for safekeeping
|
|
||||||
- View system statistics
|
|
||||||
- Optimize the database with maintenance tools
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Development
|
|
||||||
|
|
||||||
### Project Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
.
|
|
||||||
├── components/ # Templ components for UI
|
|
||||||
├── internal/
|
|
||||||
│ ├── api/ # REST API handlers
|
|
||||||
│ ├── auth/ # Authentication/authorization
|
|
||||||
│ ├── config/ # Configuration management
|
|
||||||
│ ├── db/ # Database models and operations
|
|
||||||
│ ├── email/ # Email service for notifications and password resets
|
|
||||||
│ ├── scheduler/ # Job scheduling and execution
|
|
||||||
│ └── web/ # Web interface handlers
|
|
||||||
├── static/ # Static assets
|
|
||||||
│ ├── css/
|
|
||||||
│ └── js/
|
|
||||||
└── main.go # Application entry point
|
|
||||||
```
|
|
||||||
|
|
||||||
### Technology Stack
|
|
||||||
|
|
||||||
- **Backend**: Go with Gin web framework
|
|
||||||
- **Frontend**: Templ for Go HTML components
|
|
||||||
- **UI Enhancement**: HTMX for dynamic interactions
|
|
||||||
- **Styling**: Tailwind CSS
|
|
||||||
- **Authentication**: JWT (JSON Web Tokens)
|
|
||||||
- **Database**: GORM with SQLite
|
|
||||||
- **File Transfer**: rclone
|
|
||||||
- **Deployment**: Docker containerization and traditional installation
|
|
||||||
|
|
||||||
### Building from Source
|
|
||||||
|
|
||||||
1. Install development dependencies:
|
|
||||||
```bash
|
|
||||||
go install github.com/cosmtrek/air@latest # Hot reload for development
|
|
||||||
go install github.com/a-h/templ/cmd/templ@latest # Templ template compiler
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Generate template code:
|
|
||||||
```bash
|
|
||||||
templ generate
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Run in development mode:
|
|
||||||
```bash
|
|
||||||
air
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
1. Fork the repository
|
|
||||||
2. Create a feature branch
|
|
||||||
3. Commit your changes
|
|
||||||
4. Push to the branch
|
|
||||||
5. Create a Pull Request
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Directory Structure
|
|
||||||
|
|
||||||
GoMFT uses the following directory structure:
|
|
||||||
|
|
||||||
- `/app/data`: Main application data directory
|
|
||||||
- Contains the SQLite database (`gomft.db`)
|
|
||||||
- Contains rclone configurations in `/app/data/configs`
|
|
||||||
- Contains log files in `/app/data/logs`
|
|
||||||
- `/app/backups`: Database backup directory
|
|
||||||
|
|
||||||
When using Docker, you should mount volumes to these locations:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
volumes:
|
|
||||||
- /host/path/data:/app/data # For all application data
|
|
||||||
- /host/path/backups:/app/backups # For database backups
|
|
||||||
```
|
|
||||||
|
|
||||||
These paths can be customized using the environment variables `
|
|
||||||
@@ -7,6 +7,8 @@ title: Connections
|
|||||||
|
|
||||||
Connections in GoMFT are configurations that define how to access different storage systems. Before you can transfer files, you need to set up connections for your source and destination systems.
|
Connections in GoMFT are configurations that define how to access different storage systems. Before you can transfer files, you need to set up connections for your source and destination systems.
|
||||||
|
|
||||||
|
> **Note**: GoMFT now supports the Storage Provider feature, which allows you to create reusable connection profiles with securely stored credentials. For detailed information, see the [Storage Providers](/docs/user-guides/storage-provider-guide) guide.
|
||||||
|
|
||||||
## Supported Connection Types
|
## Supported Connection Types
|
||||||
|
|
||||||
GoMFT leverages rclone as its transfer engine, supporting a wide range of storage systems:
|
GoMFT leverages rclone as its transfer engine, supporting a wide range of storage systems:
|
||||||
@@ -74,20 +76,32 @@ Different connection types require different configuration fields. Here are some
|
|||||||
|
|
||||||
GoMFT follows best practices for handling connection credentials:
|
GoMFT follows best practices for handling connection credentials:
|
||||||
|
|
||||||
- **Encryption**: All sensitive credentials are encrypted at rest
|
- **Encryption**: All sensitive credentials are encrypted at rest using AES-256 encryption
|
||||||
- **Access Control**: Connections are protected by user permissions
|
- **Access Control**: Connections are protected by user permissions
|
||||||
- **Masked Values**: Passwords and secret keys are masked in the UI
|
- **Masked Values**: Passwords and secret keys are masked in the UI
|
||||||
- **Key Management**: SSH keys and other credentials are securely stored
|
- **Key Management**: SSH keys and other credentials are securely stored
|
||||||
|
- **Centralized Management**: With the Storage Provider feature, credentials can be managed in one place and reused across multiple transfers
|
||||||
|
|
||||||
## Managing Connections
|
## Managing Connections
|
||||||
|
|
||||||
|
You can manage connections either through traditional transfer configurations or using the new Storage Provider feature.
|
||||||
|
|
||||||
### Viewing Connections
|
### Viewing Connections
|
||||||
|
|
||||||
|
#### Traditional Connections
|
||||||
|
|
||||||
The **Transfer Configurations** page displays all configured connections with:
|
The **Transfer Configurations** page displays all configured connections with:
|
||||||
- Configuration name
|
- Configuration name
|
||||||
- Configuration type
|
- Configuration type
|
||||||
- Last updated date
|
- Last updated date
|
||||||
|
|
||||||
|
#### Storage Providers
|
||||||
|
|
||||||
|
Alternatively, you can use the new Storage Provider feature to manage your connections:
|
||||||
|
1. Navigate to the **Storage Providers** section in the left sidebar
|
||||||
|
2. View a list of all storage providers you have created
|
||||||
|
3. Each provider shows name, type, and creation date
|
||||||
|
|
||||||
### Editing Transfer Confirgurations
|
### Editing Transfer Confirgurations
|
||||||
|
|
||||||
To edit an existing connection:
|
To edit an existing connection:
|
||||||
@@ -125,4 +139,6 @@ GoMFT includes a configuration testing feature to verify connectivity:
|
|||||||
- **Use service accounts** rather than personal accounts when possible
|
- **Use service accounts** rather than personal accounts when possible
|
||||||
- **Document connection details** in the description field
|
- **Document connection details** in the description field
|
||||||
- **Use the minimal required permissions** for enhanced security
|
- **Use the minimal required permissions** for enhanced security
|
||||||
- **Organize connections** using consistent naming conventions
|
- **Organize connections** using consistent naming conventions
|
||||||
|
- **Use Storage Providers** for reusable connections across multiple transfers
|
||||||
|
- **Update credentials in one place** by using Storage Providers instead of updating each transfer individually
|
||||||
@@ -157,12 +157,41 @@ When a schedule runs, GoMFT performs these actions:
|
|||||||
|
|
||||||
GoMFT provides several ways to monitor your scheduled transfers:
|
GoMFT provides several ways to monitor your scheduled transfers:
|
||||||
|
|
||||||
<!-- ### Schedule Calendar
|
### Transfer Calendar
|
||||||
|
|
||||||
View all scheduled transfers in a calendar view:
|
The Transfer Calendar provides a visual overview of all your scheduled transfers:
|
||||||
1. Navigate to **Schedule Calendar** in the Schedules section
|
|
||||||
2. See all upcoming scheduled transfers in a monthly, weekly, or daily view
|
1. Navigate to **Transfer Calendar** in the sidebar
|
||||||
3. Click on any scheduled transfer to see details or edit it -->
|
2. View all scheduled transfers in a monthly, weekly, or daily view
|
||||||
|
3. Color-coded events indicate different transfer types or statuses
|
||||||
|
4. Hover over any event to see a summary of the transfer details
|
||||||
|
5. Click on any scheduled transfer to see full details or edit it
|
||||||
|
|
||||||
|
#### Calendar Views
|
||||||
|
|
||||||
|
- **Month View**: See all scheduled transfers for the entire month
|
||||||
|
- **Week View**: Focus on transfers scheduled for the current week
|
||||||
|
- **Day View**: Detailed timeline of transfers for a specific day
|
||||||
|
- **Agenda View**: List-based view of upcoming transfers
|
||||||
|
|
||||||
|
#### Calendar Features
|
||||||
|
|
||||||
|
- **Filtering**: Filter transfers by type, status, or associated connection
|
||||||
|
<!-- - **Search**: Find specific transfers by name or description -->
|
||||||
|
<!-- - **Export**: Export calendar events to iCal or CSV format -->
|
||||||
|
<!-- - **Drag and Drop**: Reschedule transfers by dragging them to a new time slot (requires appropriate permissions) -->
|
||||||
|
<!-- - **Conflict Detection**: Visual indicators for potentially overlapping transfers -->
|
||||||
|
|
||||||
|
<!-- #### Calendar Integration
|
||||||
|
|
||||||
|
You can subscribe to the transfer calendar using external calendar applications:
|
||||||
|
|
||||||
|
1. Click the **Calendar Subscription** button
|
||||||
|
2. Copy the provided iCal URL
|
||||||
|
3. Add the URL as a calendar subscription in applications like Google Calendar, Outlook, or Apple Calendar
|
||||||
|
4. Set the refresh frequency in your calendar application
|
||||||
|
|
||||||
|
> **Note**: The calendar subscription is read-only and requires authentication. Calendar subscriptions will only show transfers that the authenticated user has permission to view. -->
|
||||||
|
|
||||||
### Transfer History
|
### Transfer History
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ title: Transfers
|
|||||||
|
|
||||||
GoMFT's primary function is to manage file transfers between different storage systems. This page explains the transfer operations available in GoMFT and how to configure them.
|
GoMFT's primary function is to manage file transfers between different storage systems. This page explains the transfer operations available in GoMFT and how to configure them.
|
||||||
|
|
||||||
|
> **Note**: GoMFT now supports the Storage Provider feature, which allows you to create reusable connection profiles for your transfers. For detailed information, see the [Storage Providers](/docs/user-guides/storage-provider-guide) guide.
|
||||||
|
|
||||||
## Transfer Types
|
## Transfer Types
|
||||||
|
|
||||||
GoMFT supports several types of transfer operations, each with different behaviors:
|
GoMFT supports several types of transfer operations, each with different behaviors:
|
||||||
@@ -51,10 +53,23 @@ When creating a transfer in GoMFT, you need to configure the following elements:
|
|||||||
|
|
||||||
- **Name**: A descriptive name for the transfer
|
- **Name**: A descriptive name for the transfer
|
||||||
- **Description**: Optional details about the transfer's purpose
|
- **Description**: Optional details about the transfer's purpose
|
||||||
- **Source**: The source connection and path
|
- **Source**: Either a direct connection configuration or a Storage Provider
|
||||||
- **Destination**: The destination connection and path
|
- **Destination**: Either a direct connection configuration or a Storage Provider
|
||||||
- **Transfer Type**: Copy, Sync, Move, or Bidirectional Sync
|
- **Transfer Type**: Copy, Sync, Move, or Bidirectional Sync
|
||||||
|
|
||||||
|
#### Using Storage Providers
|
||||||
|
|
||||||
|
When creating a transfer, you can now select a Storage Provider instead of entering connection details directly:
|
||||||
|
|
||||||
|
1. In the Source or Destination section, select **Provider** from the dropdown
|
||||||
|
2. Choose from your available Storage Providers
|
||||||
|
3. Enter the path within the selected provider
|
||||||
|
|
||||||
|
This approach offers several benefits:
|
||||||
|
- Reuse the same provider across multiple transfers
|
||||||
|
- Update credentials in one place
|
||||||
|
- Enhanced security with AES-256 encryption for credentials
|
||||||
|
|
||||||
### Advanced Options
|
### Advanced Options
|
||||||
|
|
||||||
#### File Selection
|
#### File Selection
|
||||||
@@ -147,12 +162,14 @@ When a transfer fails, GoMFT provides information to help identify the cause:
|
|||||||
|
|
||||||
1. Check the error message in the transfer history
|
1. Check the error message in the transfer history
|
||||||
2. Review the detailed logs for the specific error
|
2. Review the detailed logs for the specific error
|
||||||
3. Common issues include:
|
3. For transfers using Storage Providers, you can test the provider connection directly from the Storage Providers section
|
||||||
|
4. Common issues include:
|
||||||
- Permission problems
|
- Permission problems
|
||||||
- Network connectivity
|
- Network connectivity
|
||||||
- Invalid credentials
|
- Invalid credentials
|
||||||
- Path not found
|
- Path not found
|
||||||
- Disk space issues
|
- Disk space issues
|
||||||
|
- Expired tokens (for OAuth providers like OneDrive or Google Drive)
|
||||||
|
|
||||||
## Best Practices
|
## Best Practices
|
||||||
|
|
||||||
@@ -164,4 +181,6 @@ When a transfer fails, GoMFT provides information to help identify the cause:
|
|||||||
- **Set bandwidth limits** to avoid network congestion during peak hours
|
- **Set bandwidth limits** to avoid network congestion during peak hours
|
||||||
- **Schedule large transfers** during off-peak times
|
- **Schedule large transfers** during off-peak times
|
||||||
- **Use notifications** to stay informed about transfer results
|
- **Use notifications** to stay informed about transfer results
|
||||||
- **Regularly review logs** to identify potential issues
|
- **Regularly review logs** to identify potential issues
|
||||||
|
- **Use Storage Providers** for reusable connections across multiple transfers
|
||||||
|
- **Convert existing transfers** to use Storage Providers for easier credential management
|
||||||
@@ -15,10 +15,11 @@ Environment variables are the primary way to configure GoMFT, especially when ru
|
|||||||
|
|
||||||
| Variable | Description | Default | Example |
|
| Variable | Description | Default | Example |
|
||||||
|----------|-------------|---------|---------|
|
|----------|-------------|---------|---------|
|
||||||
| SERVER_ADDRESS | Server address and port | :8080 | `SERVER_ADDRESS=:9000` |
|
| SERVER_ADDRESS | Server address and port | :8080 | `SERVER_ADDRESS=:8080` |
|
||||||
| DATA_DIR | Main data directory | ./data | `DATA_DIR=/app/data` |
|
| DATA_DIR | Main data directory | ./data | `DATA_DIR=/app/data` |
|
||||||
| BACKUP_DIR | Directory for backups | ./backups | `BACKUP_DIR=/app/backups` |
|
| BACKUP_DIR | Directory for backups | ./backups | `BACKUP_DIR=/app/backups` |
|
||||||
| JWT_SECRET | Secret for JWT tokens | change_this_to_a_secure_random_string | `JWT_SECRET=your-secure-secret-key` |
|
| JWT_SECRET | Secret for JWT tokens | change_this_to_a_secure_random_string | `JWT_SECRET=your-secure-secret-key` |
|
||||||
|
| GOMFT_ENCRYPTION_KEY | Key used to encrypt sensitive data in the database | change_this_to_a_secure_random_string | `GOMFT_ENCRYPTION_KEY=your-secure-encryption-key` |
|
||||||
| BASE_URL | Base URL for GoMFT (used in email links) | http://localhost:8080 | `BASE_URL=https://gomft.example.com` |
|
| BASE_URL | Base URL for GoMFT (used in email links) | http://localhost:8080 | `BASE_URL=https://gomft.example.com` |
|
||||||
| SKIP_SSL_VERIFY | Skip SSL verification for outgoing webhooks/notifications | false | `SKIP_SSL_VERIFY=false` |
|
| SKIP_SSL_VERIFY | Skip SSL verification for outgoing webhooks/notifications | false | `SKIP_SSL_VERIFY=false` |
|
||||||
|
|
||||||
@@ -64,6 +65,7 @@ SERVER_ADDRESS=:8080
|
|||||||
DATA_DIR=./data
|
DATA_DIR=./data
|
||||||
BACKUP_DIR=./backups
|
BACKUP_DIR=./backups
|
||||||
JWT_SECRET=change_this_to_a_secure_random_string
|
JWT_SECRET=change_this_to_a_secure_random_string
|
||||||
|
GOMFT_ENCRYPTION_KEY=change_this_to_a_secure_random_string
|
||||||
BASE_URL=http://localhost:8080
|
BASE_URL=http://localhost:8080
|
||||||
SKIP_SSL_VERIFY=false
|
SKIP_SSL_VERIFY=false
|
||||||
|
|
||||||
@@ -111,6 +113,7 @@ docker run -d \
|
|||||||
-v /path/to/backups:/app/backups \
|
-v /path/to/backups:/app/backups \
|
||||||
-e SERVER_ADDRESS=:8080 \
|
-e SERVER_ADDRESS=:8080 \
|
||||||
-e JWT_SECRET=your-secure-secret \
|
-e JWT_SECRET=your-secure-secret \
|
||||||
|
-e GOMFT_ENCRYPTION_KEY=your-secure-encryption-key \
|
||||||
-e EMAIL_ENABLED=true \
|
-e EMAIL_ENABLED=true \
|
||||||
-e EMAIL_HOST=smtp.example.com \
|
-e EMAIL_HOST=smtp.example.com \
|
||||||
-e PUID=1000 \
|
-e PUID=1000 \
|
||||||
|
|||||||
@@ -136,6 +136,7 @@ For environments where Docker is not available or preferred, you can install GoM
|
|||||||
- Go 1.20 or later
|
- Go 1.20 or later
|
||||||
- Node.js 18 or later
|
- Node.js 18 or later
|
||||||
- gcc (for building SQLite dependencies)
|
- gcc (for building SQLite dependencies)
|
||||||
|
- templ (for generating template code)
|
||||||
|
|
||||||
### Building from Source
|
### Building from Source
|
||||||
|
|
||||||
@@ -158,13 +159,25 @@ npm install
|
|||||||
npm run build
|
npm run build
|
||||||
```
|
```
|
||||||
|
|
||||||
4. Build the Go application:
|
4. Install templ if you haven't already:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go install github.com/a-h/templ/cmd/templ@latest
|
||||||
|
```
|
||||||
|
|
||||||
|
5. Generate templ templates:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
templ generate
|
||||||
|
```
|
||||||
|
|
||||||
|
6. Build the Go application:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
go build -o gomft
|
go build -o gomft
|
||||||
```
|
```
|
||||||
|
|
||||||
5. Run the application:
|
7. Run the application:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./gomft
|
./gomft
|
||||||
|
|||||||
@@ -0,0 +1,326 @@
|
|||||||
|
---
|
||||||
|
id: storage-provider-guide
|
||||||
|
title: Storage Provider Guide
|
||||||
|
sidebar_label: Storage Providers
|
||||||
|
description: Detailed instructions for using the Storage Provider feature in GoMFT
|
||||||
|
---
|
||||||
|
|
||||||
|
# Storage Provider User Guide
|
||||||
|
|
||||||
|
This guide provides detailed instructions for using the new Storage Provider feature in GoMFT.
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
1. [Introduction](#introduction)
|
||||||
|
2. [Managing Storage Providers](#managing-storage-providers)
|
||||||
|
- [Viewing Your Storage Providers](#viewing-your-storage-providers)
|
||||||
|
- [Creating a New Storage Provider](#creating-a-new-storage-provider)
|
||||||
|
- [Editing Storage Providers](#editing-storage-providers)
|
||||||
|
- [Testing Connections](#testing-connections)
|
||||||
|
- [Deleting Storage Providers](#deleting-storage-providers)
|
||||||
|
3. [Using Storage Providers in Transfers](#using-storage-providers-in-transfers)
|
||||||
|
- [Creating Transfers with Storage Providers](#creating-transfers-with-storage-providers)
|
||||||
|
- [Converting Existing Transfers](#converting-existing-transfers)
|
||||||
|
4. [Provider Type Reference](#provider-type-reference)
|
||||||
|
- [SFTP Configuration](#sftp-configuration)
|
||||||
|
- [S3 Configuration](#s3-configuration)
|
||||||
|
- [OneDrive Configuration](#onedrive-configuration)
|
||||||
|
- [Google Drive Configuration](#google-drive-configuration)
|
||||||
|
- [FTP Configuration](#ftp-configuration)
|
||||||
|
- [SMB Configuration](#smb-configuration)
|
||||||
|
5. [Troubleshooting](#troubleshooting)
|
||||||
|
- [Common Connection Issues](#common-connection-issues)
|
||||||
|
- [Error Messages](#error-messages)
|
||||||
|
6. [FAQ](#faq)
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
The Storage Provider feature allows you to securely store and manage credentials for various storage systems. Instead of entering connection details each time you create a transfer, you can now create reusable storage provider profiles. This approach offers several benefits:
|
||||||
|
|
||||||
|
- **Improved Security**: Credentials are stored securely using AES-256 encryption
|
||||||
|
- **Simplified Management**: Update credentials in one place instead of in each transfer
|
||||||
|
- **Easier Testing**: Test connections before creating transfers
|
||||||
|
- **Reusability**: Use the same provider for multiple transfers
|
||||||
|
|
||||||
|
## Managing Storage Providers
|
||||||
|
|
||||||
|
### Viewing Your Storage Providers
|
||||||
|
|
||||||
|
To view your storage providers:
|
||||||
|
|
||||||
|
1. Navigate to the **Storage Providers** section in the left sidebar
|
||||||
|
2. You'll see a list of all storage providers you have created
|
||||||
|
3. The list shows the provider name, type, and creation date
|
||||||
|
|
||||||
|
### Creating a New Storage Provider
|
||||||
|
|
||||||
|
To create a new storage provider:
|
||||||
|
|
||||||
|
1. From the Storage Providers page, click the **Add Provider** button
|
||||||
|
2. Enter a descriptive name for the provider
|
||||||
|
3. Select the provider type from the dropdown (SFTP, S3, OneDrive, etc.)
|
||||||
|
4. Fill in the required fields for the selected provider type
|
||||||
|
5. Click **Save** to create the provider or **Save & Test** to create and test the connection
|
||||||
|
|
||||||
|
#### Example: Creating an S3 Provider
|
||||||
|
|
||||||
|
1. Name: "Company AWS S3 Bucket"
|
||||||
|
2. Type: S3
|
||||||
|
3. Fill in the required fields:
|
||||||
|
- Access Key: Your AWS access key
|
||||||
|
- Secret Key: Your AWS secret key
|
||||||
|
- Region: e.g., us-west-2
|
||||||
|
- Bucket: Your bucket name
|
||||||
|
- Endpoint: Leave blank for AWS S3 or specify for S3-compatible services
|
||||||
|
4. Click **Save & Test**
|
||||||
|
|
||||||
|
### Editing Storage Providers
|
||||||
|
|
||||||
|
To edit an existing storage provider:
|
||||||
|
|
||||||
|
1. From the Storage Providers list, click the **Edit** button next to the provider
|
||||||
|
2. Update the fields as needed
|
||||||
|
3. For security reasons, sensitive fields (passwords, secret keys) appear empty
|
||||||
|
- Leave these fields empty to keep the existing values
|
||||||
|
- Enter new values only if you want to change them
|
||||||
|
4. Click **Save** to update the provider
|
||||||
|
|
||||||
|
### Testing Connections
|
||||||
|
|
||||||
|
Testing your storage provider connections ensures they're properly configured:
|
||||||
|
|
||||||
|
1. From the Storage Providers list, click the **Test** button next to the provider
|
||||||
|
2. Or when creating/editing a provider, use the **Save & Test** button
|
||||||
|
3. The system will attempt to connect using the provided credentials
|
||||||
|
4. You'll see a success message or an error with details about what went wrong
|
||||||
|
|
||||||
|
### Deleting Storage Providers
|
||||||
|
|
||||||
|
To delete a storage provider:
|
||||||
|
|
||||||
|
1. From the Storage Providers list, click the **Delete** button next to the provider
|
||||||
|
2. A confirmation dialog will appear
|
||||||
|
- If the provider is used in any transfers, you'll see a warning listing those transfers
|
||||||
|
- You cannot delete a provider that's in use without first updating those transfers
|
||||||
|
3. Confirm deletion if the provider is not in use
|
||||||
|
|
||||||
|
## Using Storage Providers in Transfers
|
||||||
|
|
||||||
|
### Creating Transfers with Storage Providers
|
||||||
|
|
||||||
|
To create a new transfer using storage providers:
|
||||||
|
|
||||||
|
1. Navigate to the **Transfers** section and click **New Transfer**
|
||||||
|
2. Fill in the transfer name and schedule as usual
|
||||||
|
3. In the Source section, select **Provider** and choose from the dropdown
|
||||||
|
- Only providers of appropriate types will be shown
|
||||||
|
- You'll see only providers you've created (unless you're an admin)
|
||||||
|
4. In the Destination section, also select a provider
|
||||||
|
5. Configure other transfer settings as needed (paths, file patterns, etc.)
|
||||||
|
6. Click **Save** to create the transfer
|
||||||
|
|
||||||
|
### Converting Existing Transfers
|
||||||
|
|
||||||
|
Existing transfers with embedded credentials can be converted to use storage providers:
|
||||||
|
|
||||||
|
1. Edit an existing transfer
|
||||||
|
2. In the Source section, click **Convert to Provider**
|
||||||
|
- This will create a new storage provider using the embedded credentials
|
||||||
|
- The provider will be named based on the transfer name
|
||||||
|
3. Do the same for the Destination section if needed
|
||||||
|
4. Click **Save** to update the transfer
|
||||||
|
|
||||||
|
## Provider Type Reference
|
||||||
|
|
||||||
|
### SFTP Configuration
|
||||||
|
|
||||||
|
Required fields:
|
||||||
|
- **Host**: The hostname or IP address of the SFTP server
|
||||||
|
- **Port**: Server port (usually 22)
|
||||||
|
- **Username**: Your SFTP username
|
||||||
|
- **Authentication Method**: Password or Key File
|
||||||
|
- **Password**: Your SFTP password (if using password authentication)
|
||||||
|
- **Key File**: Path to SSH private key file (if using key authentication)
|
||||||
|
|
||||||
|
Optional fields:
|
||||||
|
- **Key File Password**: Password for the key file (if the key is password-protected)
|
||||||
|
|
||||||
|
Example configuration:
|
||||||
|
```
|
||||||
|
Name: Company SFTP Server
|
||||||
|
Type: SFTP
|
||||||
|
Host: sftp.example.com
|
||||||
|
Port: 22
|
||||||
|
Username: user123
|
||||||
|
Authentication: Password
|
||||||
|
Password: ********
|
||||||
|
```
|
||||||
|
|
||||||
|
### S3 Configuration
|
||||||
|
|
||||||
|
Required fields:
|
||||||
|
- **Access Key**: Your S3 access key ID
|
||||||
|
- **Secret Key**: Your S3 secret access key
|
||||||
|
- **Bucket**: The S3 bucket name
|
||||||
|
|
||||||
|
Optional fields:
|
||||||
|
- **Region**: The AWS region (e.g., us-east-1)
|
||||||
|
- **Endpoint**: Server URL for S3-compatible services (leave blank for AWS S3)
|
||||||
|
|
||||||
|
Example configuration:
|
||||||
|
```
|
||||||
|
Name: Analytics Data Bucket
|
||||||
|
Type: S3
|
||||||
|
Access Key: AKIAIOSFODNN7EXAMPLE
|
||||||
|
Secret Key: ********
|
||||||
|
Region: us-west-2
|
||||||
|
Bucket: data-analytics-bucket
|
||||||
|
```
|
||||||
|
|
||||||
|
### OneDrive Configuration
|
||||||
|
|
||||||
|
Required fields:
|
||||||
|
- **Client ID**: Your Microsoft application client ID
|
||||||
|
- **Client Secret**: Your Microsoft application client secret
|
||||||
|
- **Refresh Token**: OAuth refresh token for authentication
|
||||||
|
|
||||||
|
Optional fields:
|
||||||
|
- **Drive ID**: Specific drive ID (for accessing shared or team drives)
|
||||||
|
|
||||||
|
Example configuration:
|
||||||
|
```
|
||||||
|
Name: Marketing OneDrive
|
||||||
|
Type: OneDrive
|
||||||
|
Client ID: 12345678-1234-1234-1234-123456789012
|
||||||
|
Client Secret: ********
|
||||||
|
Refresh Token: ********
|
||||||
|
```
|
||||||
|
|
||||||
|
### Google Drive Configuration
|
||||||
|
|
||||||
|
Required fields:
|
||||||
|
- **Client ID**: Your Google API client ID
|
||||||
|
- **Client Secret**: Your Google API client secret
|
||||||
|
- **Refresh Token**: OAuth refresh token for authentication
|
||||||
|
|
||||||
|
Optional fields:
|
||||||
|
- **Team Drive**: Team drive ID (for accessing shared drives)
|
||||||
|
|
||||||
|
Example configuration:
|
||||||
|
```
|
||||||
|
Name: Sales Team Drive
|
||||||
|
Type: Google Drive
|
||||||
|
Client ID: 123456789012-abcdefghijklmnopqrstuvwxyz.apps.googleusercontent.com
|
||||||
|
Client Secret: ********
|
||||||
|
Refresh Token: ********
|
||||||
|
Team Drive: 0ABCDEFGhijklMNOPQrstuvwxyz
|
||||||
|
```
|
||||||
|
|
||||||
|
### FTP Configuration
|
||||||
|
|
||||||
|
Required fields:
|
||||||
|
- **Host**: The hostname or IP address of the FTP server
|
||||||
|
- **Port**: Server port (usually 21)
|
||||||
|
- **Username**: Your FTP username
|
||||||
|
- **Password**: Your FTP password
|
||||||
|
|
||||||
|
Optional fields:
|
||||||
|
- **Passive Mode**: Enable/disable passive mode (default: enabled)
|
||||||
|
|
||||||
|
Example configuration:
|
||||||
|
```
|
||||||
|
Name: Legacy FTP Server
|
||||||
|
Type: FTP
|
||||||
|
Host: ftp.example.com
|
||||||
|
Port: 21
|
||||||
|
Username: ftpuser
|
||||||
|
Password: ********
|
||||||
|
Passive Mode: Enabled
|
||||||
|
```
|
||||||
|
|
||||||
|
### SMB Configuration
|
||||||
|
|
||||||
|
Required fields:
|
||||||
|
- **Host**: The hostname or IP address of the SMB/CIFS server
|
||||||
|
- **Share**: The share name
|
||||||
|
- **Username**: Your username
|
||||||
|
- **Password**: Your password
|
||||||
|
|
||||||
|
Optional fields:
|
||||||
|
- **Domain**: Windows domain (if applicable)
|
||||||
|
- **Port**: Server port (default: 445)
|
||||||
|
|
||||||
|
Example configuration:
|
||||||
|
```
|
||||||
|
Name: Finance Share
|
||||||
|
Type: SMB
|
||||||
|
Host: fileserver.example.com
|
||||||
|
Share: finance
|
||||||
|
Username: jsmith
|
||||||
|
Password: ********
|
||||||
|
Domain: EXAMPLE
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Common Connection Issues
|
||||||
|
|
||||||
|
#### SFTP Connection Problems
|
||||||
|
|
||||||
|
- **Authentication Failed**: Verify username and password/key file
|
||||||
|
- **Host Not Found**: Check hostname and network connectivity
|
||||||
|
- **Permission Denied**: Ensure the user has proper permissions on the server
|
||||||
|
- **Connection Timeout**: Check firewall settings and server availability
|
||||||
|
|
||||||
|
#### S3 Connection Problems
|
||||||
|
|
||||||
|
- **Access Denied**: Verify access key, secret key, and bucket permissions
|
||||||
|
- **Invalid Region**: Ensure the region matches the bucket's region
|
||||||
|
- **No Such Bucket**: Verify the bucket name and existence
|
||||||
|
- **Endpoint Error**: For S3-compatible services, verify the endpoint URL
|
||||||
|
|
||||||
|
#### OAuth Provider Issues (OneDrive/Google Drive)
|
||||||
|
|
||||||
|
- **Invalid Client**: Verify client ID and secret
|
||||||
|
- **Token Expired**: Refresh tokens may need to be regenerated
|
||||||
|
- **Permission Scope**: Ensure the token has appropriate scopes for file access
|
||||||
|
- **Rate Limiting**: You may be making too many requests in a short period
|
||||||
|
|
||||||
|
### Error Messages
|
||||||
|
|
||||||
|
Common error messages and their solutions:
|
||||||
|
|
||||||
|
| Error Message | Possible Cause | Solution |
|
||||||
|
|---------------|----------------|----------|
|
||||||
|
| "Connection refused" | Server is not running or blocked by firewall | Check server status and firewall settings |
|
||||||
|
| "Authentication failed" | Incorrect credentials | Verify username/password or key file |
|
||||||
|
| "Invalid access key" | Incorrect or expired AWS credentials | Check your access key ID and regenerate if needed |
|
||||||
|
| "Permission denied" | Insufficient permissions | Check file/folder permissions on the server |
|
||||||
|
| "Connection timed out" | Network issue or server unavailable | Check network connectivity and server status |
|
||||||
|
| "No such file or directory" | Path does not exist | Verify the path exists on the server |
|
||||||
|
|
||||||
|
## FAQ
|
||||||
|
|
||||||
|
**Q: Can I use the same storage provider for multiple transfers?**
|
||||||
|
A: Yes, that's one of the main benefits. Create the provider once and use it in as many transfers as needed.
|
||||||
|
|
||||||
|
**Q: Can I see the passwords or secret keys I've stored?**
|
||||||
|
A: No, for security reasons, passwords and secret keys are never displayed after they're saved. You can update them, but you cannot view the existing values.
|
||||||
|
|
||||||
|
**Q: What happens if I need to update credentials?**
|
||||||
|
A: Edit the storage provider and enter the new credentials. All transfers using that provider will automatically use the updated credentials.
|
||||||
|
|
||||||
|
**Q: Are my credentials secure?**
|
||||||
|
A: Yes, all sensitive information is encrypted using AES-256 encryption before being stored in the database.
|
||||||
|
|
||||||
|
**Q: Can other users see my storage providers?**
|
||||||
|
A: No, each user can only see and use their own storage providers unless they have administrator privileges.
|
||||||
|
|
||||||
|
**Q: Can I export or import storage providers?**
|
||||||
|
A: Not currently. For security reasons, credential export is not supported.
|
||||||
|
|
||||||
|
**Q: What if I'm not sure if a provider is in use?**
|
||||||
|
A: When attempting to delete a provider, the system will show you all transfers that use it. You can also see usage information in the provider details.
|
||||||
|
|
||||||
|
**Q: Can I test a provider without creating a transfer?**
|
||||||
|
A: Yes, use the "Test" button on the provider list.
|
||||||
@@ -29,6 +29,11 @@ const sidebars: SidebarsConfig = {
|
|||||||
label: 'Core Concepts',
|
label: 'Core Concepts',
|
||||||
items: ['core-concepts/transfers', 'core-concepts/connections', 'core-concepts/schedules', 'core-concepts/monitoring'],
|
items: ['core-concepts/transfers', 'core-concepts/connections', 'core-concepts/schedules', 'core-concepts/monitoring'],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
type: 'category',
|
||||||
|
label: 'User Guides',
|
||||||
|
items: ['user-guides/storage-provider-guide'],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
type: 'category',
|
type: 'category',
|
||||||
label: 'Advanced Features',
|
label: 'Advanced Features',
|
||||||
|
|||||||
+57
-16
@@ -1,6 +1,8 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/base64"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -9,14 +11,15 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
ServerAddress string `json:"server_address"`
|
ServerAddress string `json:"server_address"`
|
||||||
DataDir string `json:"data_dir"`
|
DataDir string `json:"data_dir"`
|
||||||
BackupDir string `json:"backup_dir"`
|
BackupDir string `json:"backup_dir"`
|
||||||
JWTSecret string `json:"jwt_secret"`
|
JWTSecret string `json:"jwt_secret"`
|
||||||
Email EmailConfig `json:"email"`
|
Email EmailConfig `json:"email"`
|
||||||
BaseURL string `json:"base_url"` // Base URL for generating links in emails
|
BaseURL string `json:"base_url"` // Base URL for generating links in emails
|
||||||
TOTPEncryptKey string `json:"totp_encrypt_key"` // Encryption key for TOTP secrets
|
TOTPEncryptKey string `json:"totp_encrypt_key"` // Encryption key for TOTP secrets
|
||||||
SkipSSLVerify bool `json:"skip_ssl_verify"` // Skip SSL verification for outgoing webhooks/notifications
|
GOMFTEncryptionKey string `json:"gomft_encryption_key"` // Encryption key for database
|
||||||
|
SkipSSLVerify bool `json:"skip_ssl_verify"` // Skip SSL verification for outgoing webhooks/notifications
|
||||||
}
|
}
|
||||||
|
|
||||||
type EmailConfig struct {
|
type EmailConfig struct {
|
||||||
@@ -33,15 +36,37 @@ type EmailConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Load() (*Config, error) {
|
func Load() (*Config, error) {
|
||||||
|
// Generate secure encryption keys
|
||||||
|
defaultTOTPKey, err := generateSecureKey()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultGOMFTKey, err := generateSecureKey()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only set the environment variables if they're not already defined
|
||||||
|
// This ensures user-provided keys take precedence
|
||||||
|
if os.Getenv("TOTP_ENCRYPTION_KEY") == "" {
|
||||||
|
os.Setenv("TOTP_ENCRYPTION_KEY", defaultTOTPKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
if os.Getenv("GOMFT_ENCRYPTION_KEY") == "" {
|
||||||
|
os.Setenv("GOMFT_ENCRYPTION_KEY", defaultGOMFTKey)
|
||||||
|
}
|
||||||
|
|
||||||
// Default configuration
|
// Default configuration
|
||||||
cfg := &Config{
|
cfg := &Config{
|
||||||
ServerAddress: ":8080",
|
ServerAddress: ":8080",
|
||||||
DataDir: "./data",
|
DataDir: "./data",
|
||||||
BackupDir: "./backups",
|
BackupDir: "./backups",
|
||||||
JWTSecret: "change_this_to_a_secure_random_string",
|
JWTSecret: "change_this_to_a_secure_random_string",
|
||||||
BaseURL: "http://localhost:8080",
|
BaseURL: "http://localhost:8080",
|
||||||
TOTPEncryptKey: "this-is-a-dev-key-not-for-production!", // Default development key
|
TOTPEncryptKey: defaultTOTPKey, // Secure randomly generated key
|
||||||
SkipSSLVerify: false, // Default to verifying SSL
|
GOMFTEncryptionKey: defaultGOMFTKey, // Secure randomly generated key
|
||||||
|
SkipSSLVerify: false, // Default to verifying SSL
|
||||||
Email: EmailConfig{
|
Email: EmailConfig{
|
||||||
Enabled: false,
|
Enabled: false,
|
||||||
Host: "smtp.example.com",
|
Host: "smtp.example.com",
|
||||||
@@ -87,7 +112,9 @@ func Load() (*Config, error) {
|
|||||||
if totpKey := os.Getenv("TOTP_ENCRYPTION_KEY"); totpKey != "" {
|
if totpKey := os.Getenv("TOTP_ENCRYPTION_KEY"); totpKey != "" {
|
||||||
cfg.TOTPEncryptKey = totpKey
|
cfg.TOTPEncryptKey = totpKey
|
||||||
}
|
}
|
||||||
|
if gomftKey := os.Getenv("GOMFT_ENCRYPTION_KEY"); gomftKey != "" {
|
||||||
|
cfg.GOMFTEncryptionKey = gomftKey
|
||||||
|
}
|
||||||
// Email configuration
|
// Email configuration
|
||||||
if emailEnabled := os.Getenv("EMAIL_ENABLED"); emailEnabled != "" {
|
if emailEnabled := os.Getenv("EMAIL_ENABLED"); emailEnabled != "" {
|
||||||
cfg.Email.Enabled = strings.ToLower(emailEnabled) == "true"
|
cfg.Email.Enabled = strings.ToLower(emailEnabled) == "true"
|
||||||
@@ -145,6 +172,7 @@ func Load() (*Config, error) {
|
|||||||
"",
|
"",
|
||||||
"# Two-Factor Authentication configuration",
|
"# Two-Factor Authentication configuration",
|
||||||
"TOTP_ENCRYPTION_KEY=" + cfg.TOTPEncryptKey,
|
"TOTP_ENCRYPTION_KEY=" + cfg.TOTPEncryptKey,
|
||||||
|
"GOMFT_ENCRYPTION_KEY=" + cfg.GOMFTEncryptionKey,
|
||||||
"",
|
"",
|
||||||
"# Email configuration",
|
"# Email configuration",
|
||||||
"EMAIL_ENABLED=" + strconv.FormatBool(cfg.Email.Enabled),
|
"EMAIL_ENABLED=" + strconv.FormatBool(cfg.Email.Enabled),
|
||||||
@@ -171,3 +199,16 @@ func Load() (*Config, error) {
|
|||||||
|
|
||||||
return cfg, nil
|
return cfg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// generateSecureKey creates a cryptographically secure random key encoded as base64
|
||||||
|
func generateSecureKey() (string, error) {
|
||||||
|
// Generate 32 bytes of random data (256 bits)
|
||||||
|
bytes := make([]byte, 32)
|
||||||
|
_, err := rand.Read(bytes)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode as base64
|
||||||
|
return base64.StdEncoding.EncodeToString(bytes), nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -99,9 +99,21 @@ func (h *Handlers) HandleCreateStorageProvider(c *gin.Context) {
|
|||||||
// Set created by
|
// Set created by
|
||||||
provider.CreatedBy = userID
|
provider.CreatedBy = userID
|
||||||
|
|
||||||
|
// Start a transaction
|
||||||
|
tx := h.DB.Begin()
|
||||||
|
if tx.Error != nil {
|
||||||
|
ctx := components.CreateTemplateContext(c)
|
||||||
|
_ = components.StorageProviderForm(ctx, components.StorageProviderFormData{
|
||||||
|
Provider: &provider,
|
||||||
|
IsEdit: false,
|
||||||
|
Error: "Failed to begin transaction",
|
||||||
|
}).Render(ctx, c.Writer)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Create provider in database
|
// Create provider in database
|
||||||
err := h.DB.CreateStorageProvider(&provider)
|
if err := tx.Create(&provider).Error; err != nil {
|
||||||
if err != nil {
|
tx.Rollback()
|
||||||
ctx := components.CreateTemplateContext(c)
|
ctx := components.CreateTemplateContext(c)
|
||||||
_ = components.StorageProviderForm(ctx, components.StorageProviderFormData{
|
_ = components.StorageProviderForm(ctx, components.StorageProviderFormData{
|
||||||
Provider: &provider,
|
Provider: &provider,
|
||||||
@@ -111,6 +123,48 @@ func (h *Handlers) HandleCreateStorageProvider(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create audit log
|
||||||
|
auditDetails := map[string]interface{}{
|
||||||
|
"name": provider.Name,
|
||||||
|
"type": provider.Type,
|
||||||
|
"host": provider.Host,
|
||||||
|
"port": provider.Port,
|
||||||
|
"username": provider.Username,
|
||||||
|
}
|
||||||
|
|
||||||
|
auditLog := db.AuditLog{
|
||||||
|
Action: "create",
|
||||||
|
EntityType: "storage_provider",
|
||||||
|
EntityID: provider.ID,
|
||||||
|
UserID: userID,
|
||||||
|
Details: auditDetails,
|
||||||
|
Timestamp: time.Now(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := tx.Create(&auditLog).Error; err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
log.Printf("Error creating audit log: %v", err)
|
||||||
|
ctx := components.CreateTemplateContext(c)
|
||||||
|
_ = components.StorageProviderForm(ctx, components.StorageProviderFormData{
|
||||||
|
Provider: &provider,
|
||||||
|
IsEdit: false,
|
||||||
|
Error: "Failed to create audit log",
|
||||||
|
}).Render(ctx, c.Writer)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Commit the transaction
|
||||||
|
if err := tx.Commit().Error; err != nil {
|
||||||
|
log.Printf("Error committing transaction: %v", err)
|
||||||
|
ctx := components.CreateTemplateContext(c)
|
||||||
|
_ = components.StorageProviderForm(ctx, components.StorageProviderFormData{
|
||||||
|
Provider: &provider,
|
||||||
|
IsEdit: false,
|
||||||
|
Error: "Failed to commit transaction",
|
||||||
|
}).Render(ctx, c.Writer)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Test if requested
|
// Test if requested
|
||||||
if c.PostForm("test") == "true" {
|
if c.PostForm("test") == "true" {
|
||||||
// Create connector service
|
// Create connector service
|
||||||
@@ -218,9 +272,51 @@ func (h *Handlers) HandleUpdateStorageProvider(c *gin.Context) {
|
|||||||
provider.EncryptedRefreshToken = existingProvider.EncryptedRefreshToken
|
provider.EncryptedRefreshToken = existingProvider.EncryptedRefreshToken
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start a transaction
|
||||||
|
tx := h.DB.Begin()
|
||||||
|
if tx.Error != nil {
|
||||||
|
ctx := components.CreateTemplateContext(c)
|
||||||
|
_ = components.StorageProviderForm(ctx, components.StorageProviderFormData{
|
||||||
|
Provider: &provider,
|
||||||
|
IsEdit: true,
|
||||||
|
Error: "Failed to begin transaction",
|
||||||
|
}).Render(ctx, c.Writer)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create audit log before update
|
||||||
|
auditDetails := map[string]interface{}{
|
||||||
|
"name": provider.Name,
|
||||||
|
"type": provider.Type,
|
||||||
|
"host": provider.Host,
|
||||||
|
"port": provider.Port,
|
||||||
|
"username": provider.Username,
|
||||||
|
}
|
||||||
|
|
||||||
|
auditLog := db.AuditLog{
|
||||||
|
Action: "update",
|
||||||
|
EntityType: "storage_provider",
|
||||||
|
EntityID: provider.ID,
|
||||||
|
UserID: userID,
|
||||||
|
Details: auditDetails,
|
||||||
|
Timestamp: time.Now(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := tx.Create(&auditLog).Error; err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
log.Printf("Error creating audit log: %v", err)
|
||||||
|
ctx := components.CreateTemplateContext(c)
|
||||||
|
_ = components.StorageProviderForm(ctx, components.StorageProviderFormData{
|
||||||
|
Provider: &provider,
|
||||||
|
IsEdit: true,
|
||||||
|
Error: "Failed to create audit log",
|
||||||
|
}).Render(ctx, c.Writer)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Update provider in database
|
// Update provider in database
|
||||||
err = h.DB.UpdateStorageProvider(&provider)
|
if err := tx.Save(&provider).Error; err != nil {
|
||||||
if err != nil {
|
tx.Rollback()
|
||||||
ctx := components.CreateTemplateContext(c)
|
ctx := components.CreateTemplateContext(c)
|
||||||
_ = components.StorageProviderForm(ctx, components.StorageProviderFormData{
|
_ = components.StorageProviderForm(ctx, components.StorageProviderFormData{
|
||||||
Provider: &provider,
|
Provider: &provider,
|
||||||
@@ -230,6 +326,18 @@ func (h *Handlers) HandleUpdateStorageProvider(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Commit the transaction
|
||||||
|
if err := tx.Commit().Error; err != nil {
|
||||||
|
log.Printf("Error committing transaction: %v", err)
|
||||||
|
ctx := components.CreateTemplateContext(c)
|
||||||
|
_ = components.StorageProviderForm(ctx, components.StorageProviderFormData{
|
||||||
|
Provider: &provider,
|
||||||
|
IsEdit: true,
|
||||||
|
Error: "Failed to commit transaction",
|
||||||
|
}).Render(ctx, c.Writer)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Test if requested
|
// Test if requested
|
||||||
if c.PostForm("test") == "true" {
|
if c.PostForm("test") == "true" {
|
||||||
// Create connector service
|
// Create connector service
|
||||||
@@ -286,13 +394,67 @@ func (h *Handlers) HandleDeleteStorageProvider(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get provider
|
||||||
|
var provider db.StorageProvider
|
||||||
|
if err := h.DB.First(&provider, id).Error; err != nil {
|
||||||
|
c.JSON(http.StatusNotFound, gin.H{"error": "Storage provider not found"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if user owns this provider
|
||||||
|
if provider.CreatedBy != c.GetUint("userID") {
|
||||||
|
// Check if user is admin
|
||||||
|
isAdmin, exists := c.Get("isAdmin")
|
||||||
|
if !exists || isAdmin != true {
|
||||||
|
c.JSON(http.StatusForbidden, gin.H{"error": "You do not have permission to delete this provider"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start a transaction
|
||||||
|
tx := h.DB.Begin()
|
||||||
|
if tx.Error != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to begin transaction"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create audit log before deletion
|
||||||
|
auditDetails := map[string]interface{}{
|
||||||
|
"name": provider.Name,
|
||||||
|
"type": provider.Type,
|
||||||
|
"host": provider.Host,
|
||||||
|
"port": provider.Port,
|
||||||
|
"username": provider.Username,
|
||||||
|
}
|
||||||
|
|
||||||
|
auditLog := db.AuditLog{
|
||||||
|
Action: "delete",
|
||||||
|
EntityType: "storage_provider",
|
||||||
|
EntityID: provider.ID,
|
||||||
|
UserID: c.GetUint("userID"),
|
||||||
|
Details: auditDetails,
|
||||||
|
Timestamp: time.Now(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := tx.Create(&auditLog).Error; err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create audit log"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Delete provider
|
// Delete provider
|
||||||
err = h.DB.DeleteStorageProvider(uint(id))
|
if err := tx.Delete(&provider).Error; err != nil {
|
||||||
if err != nil {
|
tx.Rollback()
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("Failed to delete provider: %v", err)})
|
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("Failed to delete provider: %v", err)})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Commit the transaction
|
||||||
|
if err := tx.Commit().Error; err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to commit transaction"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
c.Header("HX-Refresh", "true")
|
c.Header("HX-Refresh", "true")
|
||||||
c.JSON(http.StatusOK, gin.H{"message": "Provider deleted successfully"})
|
c.JSON(http.StatusOK, gin.H{"message": "Provider deleted successfully"})
|
||||||
}
|
}
|
||||||
@@ -376,13 +538,52 @@ func (h *Handlers) HandleDuplicateStorageProvider(c *gin.Context) {
|
|||||||
duplicateProvider.UpdatedAt = time.Now()
|
duplicateProvider.UpdatedAt = time.Now()
|
||||||
// Deep copy pointer fields here if any are added in the future
|
// Deep copy pointer fields here if any are added in the future
|
||||||
|
|
||||||
// Save the duplicate
|
// Start a transaction
|
||||||
err = h.DB.CreateStorageProvider(&duplicateProvider)
|
tx := h.DB.Begin()
|
||||||
if err != nil {
|
if tx.Error != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to begin transaction"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the duplicate in the database
|
||||||
|
if err := tx.Create(&duplicateProvider).Error; err != nil {
|
||||||
|
tx.Rollback()
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create duplicate provider: " + err.Error()})
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create duplicate provider: " + err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create audit log for duplication
|
||||||
|
auditDetails := map[string]interface{}{
|
||||||
|
"name": duplicateProvider.Name,
|
||||||
|
"type": duplicateProvider.Type,
|
||||||
|
"original_id": originalProvider.ID,
|
||||||
|
"original_name": originalProvider.Name,
|
||||||
|
"host": duplicateProvider.Host,
|
||||||
|
"port": duplicateProvider.Port,
|
||||||
|
"username": duplicateProvider.Username,
|
||||||
|
}
|
||||||
|
|
||||||
|
auditLog := db.AuditLog{
|
||||||
|
Action: "duplicate",
|
||||||
|
EntityType: "storage_provider",
|
||||||
|
EntityID: duplicateProvider.ID,
|
||||||
|
UserID: userID,
|
||||||
|
Details: auditDetails,
|
||||||
|
Timestamp: time.Now(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := tx.Create(&auditLog).Error; err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create audit log"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Commit the transaction
|
||||||
|
if err := tx.Commit().Error; err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to commit transaction"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
c.Header("HX-Refresh", "true")
|
c.Header("HX-Refresh", "true")
|
||||||
c.JSON(http.StatusOK, gin.H{"message": "Provider duplicated successfully"})
|
c.JSON(http.StatusOK, gin.H{"message": "Provider duplicated successfully"})
|
||||||
}
|
}
|
||||||
|
|||||||
-411
@@ -1,411 +0,0 @@
|
|||||||
# GoMFT Testing Guide
|
|
||||||
|
|
||||||
This document outlines the testing strategy and approaches for the GoMFT application.
|
|
||||||
|
|
||||||
## Testing Structure
|
|
||||||
|
|
||||||
The test suite is organized by components, following Go's standard pattern of placing test files alongside the code they test. For each package, we create corresponding `*_test.go` files.
|
|
||||||
|
|
||||||
## Test Types
|
|
||||||
|
|
||||||
### 1. Unit Tests
|
|
||||||
|
|
||||||
Unit tests focus on testing individual functions and components in isolation. Examples include:
|
|
||||||
|
|
||||||
- Configuration loading and validation
|
|
||||||
- Password hashing and validation
|
|
||||||
- JWT token generation and validation
|
|
||||||
- Database operations
|
|
||||||
|
|
||||||
### 2. Integration Tests
|
|
||||||
|
|
||||||
Integration tests verify that different components work together correctly. Examples include:
|
|
||||||
|
|
||||||
- Database operations that span multiple tables
|
|
||||||
- Authentication flows that involve multiple components
|
|
||||||
- File transfer operations that involve multiple services
|
|
||||||
|
|
||||||
### 3. API Tests
|
|
||||||
|
|
||||||
API tests verify HTTP endpoints and request handling. Examples include:
|
|
||||||
|
|
||||||
- Authentication endpoints
|
|
||||||
- CRUD operations on resources
|
|
||||||
- File transfer management endpoints
|
|
||||||
|
|
||||||
### 4. Webhook Tests
|
|
||||||
|
|
||||||
Webhook tests verify the correct functioning of the webhook notification system. Examples include:
|
|
||||||
|
|
||||||
- Webhook URL validation during job creation/update
|
|
||||||
- Webhook headers JSON validation
|
|
||||||
- Webhook delivery when jobs complete successfully
|
|
||||||
- Webhook delivery when jobs fail
|
|
||||||
- HMAC-SHA256 signature generation and verification
|
|
||||||
- Custom HTTP headers inclusion in webhook requests
|
|
||||||
|
|
||||||
### 5. Admin Tool Tests
|
|
||||||
|
|
||||||
Admin Tool tests verify the functionality of administrative interfaces. Examples include:
|
|
||||||
|
|
||||||
- Log Viewer functionality
|
|
||||||
- Database backup and restore operations
|
|
||||||
- System statistics reporting
|
|
||||||
- Maintenance functions (e.g., VACUUM)
|
|
||||||
|
|
||||||
## Testing Utilities
|
|
||||||
|
|
||||||
A central `testutils` package provides common utilities for testing:
|
|
||||||
|
|
||||||
- Database setup with in-memory SQLite
|
|
||||||
- Test user creation
|
|
||||||
- JWT token generation
|
|
||||||
- Configuration setup
|
|
||||||
|
|
||||||
## Running Tests
|
|
||||||
|
|
||||||
To run all tests:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
go test ./...
|
|
||||||
```
|
|
||||||
|
|
||||||
To run tests for a specific package:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
go test ./internal/db
|
|
||||||
```
|
|
||||||
|
|
||||||
To run a specific test:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
go test ./internal/db -run TestUserCRUD
|
|
||||||
```
|
|
||||||
|
|
||||||
To see test coverage:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
go test ./... -cover
|
|
||||||
```
|
|
||||||
|
|
||||||
For a detailed HTML coverage report:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
go test ./... -coverprofile=coverage.out
|
|
||||||
go tool cover -html=coverage.out
|
|
||||||
```
|
|
||||||
|
|
||||||
## Mocking
|
|
||||||
|
|
||||||
For components that depend on external services or complex dependencies, we use mocking techniques:
|
|
||||||
|
|
||||||
- In-memory SQLite for database tests
|
|
||||||
- Mock schedulers for job scheduling tests
|
|
||||||
- Mock email services for email tests
|
|
||||||
- Mock HTTP servers for webhook receiver tests
|
|
||||||
- Mock file system for Log Viewer tests
|
|
||||||
|
|
||||||
### Webhook Testing Mocks
|
|
||||||
|
|
||||||
For webhook testing, implement the following mocks:
|
|
||||||
|
|
||||||
```go
|
|
||||||
// Example webhook receiver mock
|
|
||||||
func setupWebhookMock(t *testing.T) (string, chan []byte, chan http.Header) {
|
|
||||||
payloadCh := make(chan []byte, 1)
|
|
||||||
headersCh := make(chan http.Header, 1)
|
|
||||||
|
|
||||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
body, _ := io.ReadAll(r.Body)
|
|
||||||
payloadCh <- body
|
|
||||||
headersCh <- r.Header.Clone()
|
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
}))
|
|
||||||
|
|
||||||
t.Cleanup(func() {
|
|
||||||
server.Close()
|
|
||||||
})
|
|
||||||
|
|
||||||
return server.URL, payloadCh, headersCh
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Log Viewer Testing Mocks
|
|
||||||
|
|
||||||
For Log Viewer testing, implement file system mocks:
|
|
||||||
|
|
||||||
```go
|
|
||||||
// Example log file system mock
|
|
||||||
func setupLogFilesMock(t *testing.T) string {
|
|
||||||
tempDir := t.TempDir()
|
|
||||||
|
|
||||||
// Create sample log files
|
|
||||||
for i, content := range []string{
|
|
||||||
"INFO: Test log entry 1\nERROR: Test error\n",
|
|
||||||
"INFO: Test log entry 2\nWARN: Test warning\n",
|
|
||||||
} {
|
|
||||||
filename := fmt.Sprintf("test_log_%d.log", i)
|
|
||||||
err := os.WriteFile(filepath.Join(tempDir, filename), []byte(content), 0644)
|
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return tempDir
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Test Data
|
|
||||||
|
|
||||||
Test data should be created programmatically rather than relying on existing data in the database. This ensures tests are repeatable and isolated.
|
|
||||||
|
|
||||||
## Continuous Integration
|
|
||||||
|
|
||||||
Tests are automatically run as part of the CI pipeline to ensure code quality and prevent regressions.
|
|
||||||
|
|
||||||
## Example Tests
|
|
||||||
|
|
||||||
Here are examples of different types of tests:
|
|
||||||
|
|
||||||
### Configuration Test Example
|
|
||||||
|
|
||||||
```go
|
|
||||||
// See internal/config/config_test.go
|
|
||||||
func TestLoad(t *testing.T) {
|
|
||||||
// Test loading configuration from environment variables
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Database Test Example
|
|
||||||
|
|
||||||
```go
|
|
||||||
// See internal/db/db_test.go
|
|
||||||
func TestUserCRUD(t *testing.T) {
|
|
||||||
// Test creating, reading, updating, and deleting users
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### HTTP Handler Test Example
|
|
||||||
|
|
||||||
```go
|
|
||||||
// See internal/web/handlers/basic_handlers_test.go
|
|
||||||
func TestHandleHome(t *testing.T) {
|
|
||||||
// Test handling home page requests
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Webhook Test Example
|
|
||||||
|
|
||||||
```go
|
|
||||||
// See internal/web/handlers/webhook_test.go
|
|
||||||
func TestWebhookValidation(t *testing.T) {
|
|
||||||
// Set up test environment
|
|
||||||
handlers, router, _, _, config := setupJobsTest(t)
|
|
||||||
|
|
||||||
// Add job create route
|
|
||||||
router.POST("/jobs/create", handlers.HandleCreateJob)
|
|
||||||
|
|
||||||
// Create job form data with invalid webhook URL
|
|
||||||
formData := url.Values{
|
|
||||||
"name": {"Invalid Webhook Job"},
|
|
||||||
"config_ids[]": {strconv.Itoa(int(config.ID))},
|
|
||||||
"schedule": {"*/15 * * * *"},
|
|
||||||
"enabled": {"true"},
|
|
||||||
"webhook_enabled": {"true"},
|
|
||||||
"webhook_url": {"invalid-url"}, // Invalid URL
|
|
||||||
"webhook_secret": {"test-secret"},
|
|
||||||
"notify_on_success": {"true"},
|
|
||||||
"notify_on_failure": {"true"},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Submit form
|
|
||||||
req, _ := http.NewRequest("POST", "/jobs/create", strings.NewReader(formData.Encode()))
|
|
||||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
||||||
resp := httptest.NewRecorder()
|
|
||||||
router.ServeHTTP(resp, req)
|
|
||||||
|
|
||||||
// Should not create job with invalid webhook URL
|
|
||||||
assert.NotEqual(t, http.StatusFound, resp.Code)
|
|
||||||
assert.Contains(t, resp.Body.String(), "valid URL")
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Admin Tools Test Example
|
|
||||||
|
|
||||||
```go
|
|
||||||
// See internal/web/handlers/admin_handlers_test.go
|
|
||||||
func TestLogViewer(t *testing.T) {
|
|
||||||
// Set up test environment with mock log files
|
|
||||||
logDir := setupLogFilesMock(t)
|
|
||||||
t.Setenv("LOGS_DIR", logDir)
|
|
||||||
|
|
||||||
handlers, router, _ := setupAdminTest(t)
|
|
||||||
|
|
||||||
// Add log viewer route
|
|
||||||
router.GET("/admin/logs/view/:filename", handlers.HandleViewLogFile)
|
|
||||||
|
|
||||||
// Create request to view log file
|
|
||||||
req, _ := http.NewRequest("GET", "/admin/logs/view/test_log_0.log", nil)
|
|
||||||
resp := httptest.NewRecorder()
|
|
||||||
|
|
||||||
// Add admin user to context
|
|
||||||
ctx, _ := gin.CreateTestContext(resp)
|
|
||||||
ctx.Set("userID", uint(1))
|
|
||||||
ctx.Set("isAdmin", true)
|
|
||||||
req = req.WithContext(ctx)
|
|
||||||
|
|
||||||
// Serve request
|
|
||||||
router.ServeHTTP(resp, req)
|
|
||||||
|
|
||||||
// Verify response contains log content
|
|
||||||
assert.Equal(t, http.StatusOK, resp.Code)
|
|
||||||
assert.Contains(t, resp.Body.String(), "Test log entry 1")
|
|
||||||
assert.Contains(t, resp.Body.String(), "Test error")
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Test Best Practices
|
|
||||||
|
|
||||||
1. **Isolation**: Each test should be independent and not rely on the state of other tests.
|
|
||||||
2. **Coverage**: Aim for high test coverage, especially for critical components.
|
|
||||||
3. **Readability**: Tests should be easy to read and understand.
|
|
||||||
4. **Performance**: Tests should run quickly to enable fast feedback cycles.
|
|
||||||
5. **Maintainability**: Tests should be easy to maintain and update as the codebase evolves.
|
|
||||||
|
|
||||||
## Recent Testing Improvements
|
|
||||||
|
|
||||||
### Database Layer Testing
|
|
||||||
|
|
||||||
The database layer has seen significant improvements in test coverage. Key improvements include:
|
|
||||||
|
|
||||||
- Comprehensive CRUD operation tests
|
|
||||||
- Error handling tests for edge cases
|
|
||||||
- Transaction tests
|
|
||||||
- Tests for database initialization and migration
|
|
||||||
|
|
||||||
### Web Handlers Testing
|
|
||||||
|
|
||||||
#### File Metadata Handlers
|
|
||||||
|
|
||||||
We've implemented comprehensive tests for the file metadata handlers:
|
|
||||||
|
|
||||||
- `ListFileMetadata`
|
|
||||||
- `GetFileMetadataDetails`
|
|
||||||
- `GetFileMetadataForJob`
|
|
||||||
- `SearchFileMetadata`
|
|
||||||
- `DeleteFileMetadata`
|
|
||||||
- `HandleFileMetadataPartial`
|
|
||||||
- `HandleFileMetadataSearchPartial`
|
|
||||||
|
|
||||||
These tests cover:
|
|
||||||
- Authentication and authorization
|
|
||||||
- Pagination
|
|
||||||
- Filtering
|
|
||||||
- Error handling
|
|
||||||
- HTMX integration
|
|
||||||
|
|
||||||
#### Testing Challenges and Solutions
|
|
||||||
|
|
||||||
When testing web handlers, we encountered several challenges:
|
|
||||||
|
|
||||||
1. **Authentication**: Tests needed to simulate authenticated users with proper permissions.
|
|
||||||
2. **HTMX Integration**: Many handlers expect HTMX headers for proper functioning.
|
|
||||||
3. **HTML Response Validation**: Validating HTML responses can be brittle.
|
|
||||||
|
|
||||||
Solutions implemented:
|
|
||||||
- Created helper functions to set up authentication context
|
|
||||||
- Added HTMX headers to test requests
|
|
||||||
- Focused on verifying database state rather than HTML content
|
|
||||||
|
|
||||||
## Next Steps for Testing
|
|
||||||
|
|
||||||
### Web Handlers
|
|
||||||
|
|
||||||
The overall coverage for the web handlers package needs improvement. To improve this, we should focus on:
|
|
||||||
|
|
||||||
1. **Authentication Handlers**: Implement tests for login, logout, and registration handlers.
|
|
||||||
2. **Job Handlers**: Test job creation, modification, and deletion handlers.
|
|
||||||
3. **Configuration Handlers**: Test transfer configuration management handlers.
|
|
||||||
4. **Dashboard Handlers**: Test dashboard data retrieval handlers.
|
|
||||||
|
|
||||||
### API Layer
|
|
||||||
|
|
||||||
The API layer currently has minimal test coverage. We should implement tests for:
|
|
||||||
|
|
||||||
1. **API Authentication**: Test API token generation and validation.
|
|
||||||
2. **API Endpoints**: Test all REST API endpoints.
|
|
||||||
3. **Error Handling**: Test API error responses.
|
|
||||||
|
|
||||||
### Scheduler
|
|
||||||
|
|
||||||
The scheduler component needs tests for:
|
|
||||||
|
|
||||||
1. **Job Scheduling**: Test scheduling and execution of jobs.
|
|
||||||
2. **Error Handling**: Test error handling during job execution.
|
|
||||||
3. **Concurrency**: Test concurrent job execution.
|
|
||||||
|
|
||||||
### Performance Testing
|
|
||||||
|
|
||||||
Implement performance tests for critical operations:
|
|
||||||
|
|
||||||
1. **File Transfer**: Test large file transfer performance.
|
|
||||||
2. **Database Operations**: Test database performance under load.
|
|
||||||
3. **API Endpoints**: Test API endpoint performance.
|
|
||||||
|
|
||||||
### Webhook Testing
|
|
||||||
|
|
||||||
The webhook functionality requires comprehensive testing:
|
|
||||||
|
|
||||||
1. **Validation Tests**:
|
|
||||||
- Ensure invalid webhook URLs are rejected during job creation/updates
|
|
||||||
- Verify malformed JSON in webhook headers is detected and rejected
|
|
||||||
- Test validation edge cases (empty URLs, very long URLs, etc.)
|
|
||||||
|
|
||||||
2. **Notification Tests**:
|
|
||||||
- Verify webhooks are sent for successful job completion when configured
|
|
||||||
- Verify webhooks are sent for failed jobs when configured
|
|
||||||
- Confirm webhooks are not sent when the feature is disabled
|
|
||||||
- Test the conditional notification settings (notify on success, notify on failure)
|
|
||||||
|
|
||||||
3. **Security Tests**:
|
|
||||||
- Verify HMAC-SHA256 signatures are correctly generated
|
|
||||||
- Test signature verification process
|
|
||||||
- Ensure webhook secrets are securely handled
|
|
||||||
|
|
||||||
4. **Integration Tests**:
|
|
||||||
- Set up a mock webhook receiver to catch and validate payloads
|
|
||||||
- Test with various job types and configurations
|
|
||||||
- Verify all expected payload fields are present and accurate
|
|
||||||
|
|
||||||
### Admin Tools Testing
|
|
||||||
|
|
||||||
The Admin Tools interface, particularly the Log Viewer, requires testing:
|
|
||||||
|
|
||||||
1. **Log Viewer Tests**:
|
|
||||||
- Verify all log files are correctly listed and accessible
|
|
||||||
- Test the log file content display functionality
|
|
||||||
- Verify log download capability works correctly
|
|
||||||
- Test refresh functionality updates the log list and content
|
|
||||||
- Verify the viewer works correctly with various log file sizes
|
|
||||||
- Test compatibility with log rotation
|
|
||||||
|
|
||||||
2. **Database Management Tests**:
|
|
||||||
- Verify backup creation and listing functionality
|
|
||||||
- Test database restore capability
|
|
||||||
- Verify backup download functionality
|
|
||||||
- Test database optimization functions
|
|
||||||
|
|
||||||
3. **System Statistics Tests**:
|
|
||||||
- Verify accurate reporting of system metrics (database size, job counts, etc.)
|
|
||||||
- Test uptime calculation and display
|
|
||||||
|
|
||||||
## Conclusion
|
|
||||||
|
|
||||||
Continued focus on testing will ensure the reliability and maintainability of the GoMFT application. By systematically addressing each component, we can achieve high test coverage and confidence in the codebase.
|
|
||||||
|
|
||||||
The recent addition of webhook notification capabilities and admin tools, including the Log Viewer, has expanded the testing requirements. These new features involve various aspects of the system, from HTTP handling to file system operations, and require a comprehensive testing approach that considers:
|
|
||||||
|
|
||||||
1. **Functionality Testing**: Ensuring the basic functionality works as expected
|
|
||||||
2. **Edge Case Testing**: Handling invalid input and extreme conditions
|
|
||||||
3. **Integration Testing**: Verifying the components work together correctly
|
|
||||||
4. **Security Testing**: Validating security measures like HMAC signatures
|
|
||||||
|
|
||||||
By implementing the testing strategies outlined in this document, we can ensure that all components of the GoMFT system, including these newer features, maintain high quality and reliability.
|
|
||||||
Reference in New Issue
Block a user