Audit sharing controls coverage
This commit is contained in:
@@ -38,6 +38,7 @@ Date: 2026-06-08.
|
||||
- Android photo/video backup settings now show a compact overall backup status: enabled state, selected phone-folder count, network/roaming/charging conditions, and last backup scan.
|
||||
- Android auto-upload now stores per-source folder sync cursors in Room schema version `52`, keeps the legacy `lastSyncTimestamp` as a migration fallback, starts newly added source folders at timestamp `0`, and preserves per-source cursors when a metered run stops at the daily mobile-data limit. `:qsferaDomain:testDebugUnitTest --tests "eu.qsfera.android.domain.automaticuploads.model.FolderBackUpConfigurationTest"`, `:qsferaApp:testOriginalDebugUnitTest --tests "eu.qsfera.android.workers.AutomaticUploadsWorkerTest"`, and `:qsferaData:compileDebugKotlin` passed on 2026-06-10.
|
||||
- Android public-link rows now show the effective access mode, password state, and expiration state directly in the share list, so users can review link safety without reopening each link. `:qsferaApp:testOriginalDebugUnitTest --tests "eu.qsfera.android.presentation.sharing.shares.PublicShareStatusFormatterTest"` and `:qsferaApp:compileOriginalDebugKotlin` passed on 2026-06-10.
|
||||
- Sharing controls were audited against the Google Drive and Yandex Disk benchmarks in `Server/docs/sharing-controls-production-audit.md`, and `scripts/verify-sharing-controls-coverage.ps1` now checks local Android UI, Graph link types, server link handling, and acceptance-feature coverage for password, expiration, access roles, internal links, secure-view/no-download behavior, and role-based resharing.
|
||||
- Server `qsfera_full` compose files now require explicit admin, Keycloak, and S3/MinIO secrets instead of demo defaults.
|
||||
- Server `qsfera_full/env.production.example` provides a tracked production-safe starting point with TLS validation enabled and demo users disabled.
|
||||
- Server `qsfera_full/validate-production-env.sh` checks production `.env` invariants before compose validation: TLS validation enabled, demo users disabled, pinned production image, required domains, required secrets, and no public-production MinIO.
|
||||
@@ -91,4 +92,4 @@ Date: 2026-06-08.
|
||||
|
||||
- Extend Android backup status UX beyond the new overall settings summary with per-item status, queued/paused/permanent-failure states, and low-storage messaging.
|
||||
- Configure `QSFERA_ALERT_WEBHOOK_URL` in `/etc/qsfera/rpi-production-check.env` if off-host alert delivery is required; the installed failure service currently logs through `systemd-cat` and journal without an external endpoint.
|
||||
- Verify sharing controls against Google Drive and Yandex Disk expectations: link expiration, password, disable downloads, organization-only access, and role inheritance.
|
||||
- Decide and implement Android-facing controls for Graph `internal` links and `blocksDownload` secure-view links, or explicitly keep them server-managed/custom-access states. Server/API coverage is documented in `Server/docs/sharing-controls-production-audit.md`; the Android public-link dialog still exposes only password, expiration, read-only, read/write, and upload-only OCS controls.
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
# QSfera Sharing Controls Production Audit
|
||||
|
||||
Date: 2026-06-10.
|
||||
|
||||
## External Benchmarks
|
||||
|
||||
- Google Drive documents file-sharing roles, per-link/general access, download control for viewers/commenters, and folder permission inheritance on its Android sharing help page: <https://support.google.com/drive/answer/2494822?co=GENIE.Platform%3DAndroid&hl=en>.
|
||||
- Yandex Disk documents mobile link security settings for view-only access, disabling downloads, link password, expiration date, and organization-only links on its Android sharing help page: <https://yandex.com/support/yandex-360/customers/disk/app/android/en/actions/share>.
|
||||
|
||||
## Verified QSfera Coverage
|
||||
|
||||
| Benchmark control | QSfera evidence | Status |
|
||||
| --- | --- | --- |
|
||||
| Public-link password | Android exposes `shareViaLinkPasswordSwitch`; Graph `CreateLink` stores `Password`; acceptance tests create and update password-protected link shares and verify old passwords fail with HTTP `401`. | Covered for Android OCS links and Graph links. |
|
||||
| Public-link expiration | Android exposes `shareViaLinkExpirationSwitch`; Graph `CreateLink` reads `expirationDateTime`; acceptance tests create, update, and remove expiration dates. | Covered for Android OCS links and Graph links. |
|
||||
| Link access role | Android exposes read-only, read/write, and upload-only radio options; Graph link types include `view`, `edit`, `upload`, and `createOnly`; acceptance tests cover those roles for files, folders, and project-space links. | Covered, with different Android OCS labels and Graph role names. |
|
||||
| Disable downloads / secure view | Graph link types include `blocksDownload`; acceptance tests also verify the `Secure Viewer` role cannot download files. Android public-link rows now display non-standard link permissions as `Custom access`. | Server/API coverage exists; Android does not expose a dedicated `blocksDownload` switch. |
|
||||
| Organization-only access | Graph link types include `internal`; frontend config documents default link permission `0` as an internal/member-only link; server rejects redundant passwords on internal links; acceptance tests create and update internal links. | Server/API coverage exists; Android does not expose a separate organization-only/internal link choice. |
|
||||
| Role inheritance / resharing | Space sharing acceptance tests verify managers can reshare spaces, editors/viewers cannot, and project-space public-link creation requires manager rights. | Covered by server acceptance scenarios. |
|
||||
|
||||
## Repeatable Local Check
|
||||
|
||||
Run from the repository root:
|
||||
|
||||
```powershell
|
||||
.\scripts\verify-sharing-controls-coverage.ps1
|
||||
```
|
||||
|
||||
The script is a static coverage gate over Android UI files, Graph link type code, server link creation code, and acceptance feature files. It does not replace a full server acceptance run.
|
||||
|
||||
## Remaining Product Gap
|
||||
|
||||
The Android public-link dialog currently exposes the OCS link controls already present in the client: password, expiration, read-only, read/write, and upload-only. It does not expose dedicated Graph `internal` or `blocksDownload` controls. If QSfera wants Android parity with Yandex Disk's organization-only and disable-download controls, the next client/server integration step is to add Android Graph-link creation/editing paths for those two link types or define an explicit product decision that Android continues to show them as server-managed/custom access states.
|
||||
@@ -0,0 +1,82 @@
|
||||
param(
|
||||
[string]$RepoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
function Fail($Message) {
|
||||
Write-Error $Message
|
||||
exit 1
|
||||
}
|
||||
|
||||
function Assert-FileContains($Name, $RelativePath, $Pattern) {
|
||||
$path = Join-Path $RepoRoot $RelativePath
|
||||
if (-not (Test-Path -LiteralPath $path)) {
|
||||
Fail "$Name source file is missing: $RelativePath"
|
||||
}
|
||||
|
||||
$content = Get-Content -LiteralPath $path -Raw
|
||||
if ($content -notmatch $Pattern) {
|
||||
Fail "$Name was not found in $RelativePath. Pattern: $Pattern"
|
||||
}
|
||||
|
||||
Write-Host "OK: $Name"
|
||||
}
|
||||
|
||||
Write-Host "Checking QSfera sharing-controls coverage..."
|
||||
|
||||
Assert-FileContains "Android public-link dialog exposes password control" `
|
||||
"Android/qsferaApp/src/main/java/eu/qsfera/android/presentation/sharing/shares/PublicShareDialogFragment.kt" `
|
||||
"shareViaLinkPasswordSwitch"
|
||||
Assert-FileContains "Android public-link dialog exposes expiration control" `
|
||||
"Android/qsferaApp/src/main/java/eu/qsfera/android/presentation/sharing/shares/PublicShareDialogFragment.kt" `
|
||||
"shareViaLinkExpirationSwitch"
|
||||
Assert-FileContains "Android public-link dialog exposes upload-only mode" `
|
||||
"Android/qsferaApp/src/main/java/eu/qsfera/android/presentation/sharing/shares/PublicShareDialogFragment.kt" `
|
||||
"shareViaLinkEditPermissionUploadFiles"
|
||||
Assert-FileContains "Android public-link rows show safety status" `
|
||||
"Android/qsferaApp/src/main/java/eu/qsfera/android/presentation/sharing/shares/SharePublicLinkListAdapter.kt" `
|
||||
"PublicShareStatusFormatter\.statusFor"
|
||||
|
||||
Assert-FileContains "Graph API declares internal link type" `
|
||||
"Server/vendor/github.com/opencloud-eu/libre-graph-api-go/model_sharing_link_type.go" `
|
||||
"INTERNAL SharingLinkType = `"internal`""
|
||||
Assert-FileContains "Graph API declares secure-view link type" `
|
||||
"Server/vendor/github.com/opencloud-eu/libre-graph-api-go/model_sharing_link_type.go" `
|
||||
"BLOCKS_DOWNLOAD SharingLinkType = `"blocksDownload`""
|
||||
Assert-FileContains "Graph API declares file-drop link type" `
|
||||
"Server/vendor/github.com/opencloud-eu/libre-graph-api-go/model_sharing_link_type.go" `
|
||||
"CREATE_ONLY SharingLinkType = `"createOnly`""
|
||||
Assert-FileContains "Server maps internal link to no public-share permissions" `
|
||||
"Server/services/graph/pkg/linktype/linktype.go" `
|
||||
"func NewInternalLinkPermissionSet\(\) \*LinkType[\s\S]*ResourcePermissions\{\}"
|
||||
Assert-FileContains "Server rejects passwords on internal links" `
|
||||
"Server/services/graph/pkg/service/v0/api_driveitem_permissions_links.go" `
|
||||
"password is redundant for the internal link"
|
||||
Assert-FileContains "Server stores link expiration during creation" `
|
||||
"Server/services/graph/pkg/service/v0/api_driveitem_permissions_links.go" `
|
||||
"GetExpirationDateTimeOk"
|
||||
|
||||
Assert-FileContains "Acceptance tests create link shares with password and expiration" `
|
||||
"Server/tests/acceptance/features/apiSharingNgLinkSharePermission/createLinkShare.feature" `
|
||||
"expirationDateTime[\s\S]*hasPassword"
|
||||
Assert-FileContains "Acceptance tests update link-share expiration" `
|
||||
"Server/tests/acceptance/features/apiSharingNgLinkSharePermission/updateLinkShare.feature" `
|
||||
"update expiration date of a file's link share"
|
||||
Assert-FileContains "Acceptance tests update link-share password and reject old password" `
|
||||
"Server/tests/acceptance/features/apiSharingNgLinkSharePermission/updateLinkShare.feature" `
|
||||
"public download of file[\s\S]*should fail with HTTP status code `"401`""
|
||||
Assert-FileContains "Acceptance tests update public links to internal links" `
|
||||
"Server/tests/acceptance/features/apiSharingNgLinkSharePermission/updateLinkShare.feature" `
|
||||
"permissionsRole \| internal"
|
||||
Assert-FileContains "Acceptance tests include secure viewer no-download behavior" `
|
||||
"Server/tests/acceptance/features/apiSharingNg1/enableDisablePermissionsRole.feature" `
|
||||
"Secure Viewer[\s\S]*should not be able to download"
|
||||
Assert-FileContains "Acceptance tests enforce space-manager sharing rights" `
|
||||
"Server/tests/acceptance/features/apiSpacesShares/shareSpaces.feature" `
|
||||
"manager role can share[\s\S]*editor or viewer role cannot share"
|
||||
Assert-FileContains "Acceptance tests enforce project-space public-link sharing rights" `
|
||||
"Server/tests/acceptance/features/apiSpacesShares/shareSubItemOfSpaceViaPublicLink.feature" `
|
||||
"space manager role can share[\s\S]*without space manager role cannot share"
|
||||
|
||||
Write-Host "QSfera sharing-controls coverage check passed."
|
||||
Reference in New Issue
Block a user