feat(file): conceal file resource existence from other users
- feat: cross-user file access returns not-found instead of permission-denied - fix: repository delete now only affects active rows and returns ErrNotFound when no row changes; repeated deletes yield not-found - feat: parent directory operations (list, upload, create-dir, move) conceal ownership of other user's directories - test: update handler, service, repository, and integration tests to assert not-found behavior for cross-user and missing file operations
This commit is contained in:
@@ -106,3 +106,20 @@
|
||||
- REST remains a handler/API concern, and future protocols can reuse services without HTTP leakage.
|
||||
- Error responses keep the same top-level shape, with optional `log_id` instead of embedding log references in the message.
|
||||
- Admin and auth middleware behavior is testable through service contracts rather than database access.
|
||||
|
||||
## 2026-07-15: Conceal File Resource Existence
|
||||
|
||||
**Context**: Returning permission-denied errors for cross-user file access allowed authenticated callers to distinguish another user's resource from a missing resource. Idempotent success for deleting missing files also conflicted with a consistent not-found concealment policy.
|
||||
|
||||
**Decisions**:
|
||||
|
||||
| Decision | Guidance |
|
||||
|----------|----------|
|
||||
| Conceal ownership | File and parent-directory ownership failures return the same not-found kind and safe message as missing or deleted resources. |
|
||||
| Strict delete result | Deleting an active owned file returns success once; missing, deleted, and cross-user targets return not found. |
|
||||
| Atomic soft delete | Repository deletes update only active rows and return `model.ErrNotFound` when no row changes. |
|
||||
|
||||
**Consequences**:
|
||||
- Authenticated file operations cannot use status codes or messages to determine whether another user's resource exists.
|
||||
- A successful first delete returns `204 No Content`; repeated deletes return `404 Not Found` while remaining idempotent in effect.
|
||||
- Unauthenticated requests remain `401 Unauthorized`, non-empty directory deletion remains `409 Conflict`, and permission-denied behavior outside the file boundary remains unchanged.
|
||||
|
||||
@@ -27,7 +27,7 @@ Package-level implementation order (each task includes unit tests):
|
||||
10. `internal/handler` — auth, account, file, admin handlers 🛠 (HTTP DTO mapping in place)
|
||||
11. `internal/server` — Gin router, route registration, graceful shutdown ✅
|
||||
12. `cmd/serve.go`, `cmd/config.go`, `cmd/status.go` ✅ (serve done)
|
||||
13. Integration tests 🛠 (authenticated register → login → upload → list → download route flow covered with a small file; file API authentication bypass, invalid token, and cross-user isolation boundaries covered)
|
||||
13. Integration tests 🛠 (authenticated register → login → upload → list → download route flow covered with a small file; authentication bypass, invalid token, concealed cross-user resources, and strict delete boundaries covered)
|
||||
14. Architecture boundary tests ✅
|
||||
|
||||
## Future
|
||||
|
||||
Reference in New Issue
Block a user