Download a file using its public access link hash. This endpoint validates access restrictions through middleware before serving the file.
Endpoint
Parameters
The unique hash identifier for the access link (e.g., abc123def456)
Access Restriction Flow
Before the file is served, the AccessRestrictions middleware enforces several security checks in this order:
1. Link Validation
- Verifies the access link exists in the database
- Returns
404 if link not found
2. File Validation
- Confirms the linked file exists
- Returns
404 if file not found
3. Public Access Check
- Both the file and the access link must have
public: true
- Returns
403 with message "Access denied: file or access is not public" if either is private
4. Subnet Restriction
- If
subnets array is non-empty, validates client IP against CIDR ranges
- Parses each subnet as CIDR notation (e.g.,
192.168.1.0/24)
- Returns
403 with message "Access restricted to specific subnets" if IP not in allowed subnets
- Skips check if
subnets array is empty
Source: middleware/access_restrictions.go:82-96
5. IP Whitelist
- If
ips array is non-empty, validates client IP against exact matches
- Returns
403 with message "Access restricted to specific IPs" if IP not in whitelist
- Skips check if
ips array is empty
Source: middleware/access_restrictions.go:98-111
6. Expiration Check
- If
expires field is set, parses as RFC3339 timestamp
- Returns
403 with message "Access link has expired" if current time is past expiration
- Skips check if
expires is empty string
Source: middleware/access_restrictions.go:61-71
7. One-Time Use Check
- If
one_time_use: true and used: true, denies access
- Returns
403 with message `“Access link has already been used”
- After successful access, marks
used: true in database
Source: middleware/access_restrictions.go:73-80
8. TTL (Time-To-Live) Decrement
- If
enable_ttl: true and ttl > 0, decrements TTL by 1
- If TTL reaches 0, returns
403 with message "Access link has reached its TTL limit"
- Persists updated TTL value to database on each access
- No action if
enable_ttl: false
Source: middleware/access_restrictions.go:113-124
The TTL counter decrements before checking if it has reached zero, meaning a TTL of 1 allows exactly one access.
Response
Success Response (200)
On successful validation, the file is served as a download with proper headers:
- Content-Disposition:
attachment; filename="{original_filename}"
- File served from:
/app/data/uploads/{username}/{filename}
The response streams the file binary content directly.
Source: controllers/link.go:109-110
Error Responses
Error message describing why access was denied
404 Not Found
{
"error": "Access link not found"
}
Or:
{
"error": "File not found"
}
403 Forbidden
Various restriction failures:
{
"error": "Access denied: file or access is not public"
}
{
"error": "Access restricted to specific subnets"
}
{
"error": "Access restricted to specific IPs"
}
{
"error": "Access link has expired"
}
{
"error": "Access link has already been used"
}
{
"error": "Access link has reached its TTL limit"
}
Implementation Notes
The controller at controllers/link.go:25 contains commented-out validation logic. All access restriction checks are now handled by the AccessRestrictions middleware at middleware/access_restrictions.go:14.
Side Effects
- One-time use: Sets
used: true after successful access (persisted to database)
- TTL: Decrements counter by 1 on each access attempt (persisted to database)
Client IP Detection
Client IP is extracted using Gin’s c.ClientIP() which respects:
X-Forwarded-For header
X-Real-IP header
- Remote address as fallback
Example Usage
curl -O -J https://api.defdrive.com/link/abc123def456
This downloads the file with its original filename preserved via the Content-Disposition header.