Audit sharing controls coverage

This commit is contained in:
Курнат Андрей
2026-06-10 07:56:02 +03:00
parent 89a8f32649
commit b3016e6c99
3 changed files with 117 additions and 1 deletions
+2 -1
View File
@@ -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."