feat(contacts): add feature flag to enable/disable exposition of users in address-book

This commit is contained in:
Edouard Vanbelle
2026-05-10 22:12:11 +02:00
parent 7e1484ec2c
commit ad711e18ea
3 changed files with 20 additions and 1 deletions
+10
View File
@@ -618,6 +618,9 @@ pub struct FeaturesConfig {
pub enable_trash: bool,
pub enable_search: bool,
pub enable_music: bool,
/// Expose other OxiCloud users as a read-only "system" address book
/// at GET /api/address-books. Set to false to hide the user directory.
pub expose_system_users: bool,
}
impl Default for FeaturesConfig {
@@ -629,6 +632,7 @@ impl Default for FeaturesConfig {
enable_trash: true, // Enable trash feature
enable_search: true, // Enable search feature
enable_music: true, // Enable music feature
expose_system_users: true, // Expose OxiCloud users as address book by default
}
}
}
@@ -948,6 +952,12 @@ impl AppConfig {
config.features.enable_music = val;
}
if let Ok(v) = env::var("OXICLOUD_EXPOSE_SYSTEM_USERS").map(|v| v.parse::<bool>())
&& let Ok(val) = v
{
config.features.expose_system_users = val;
}
// Storage limits
if let Ok(max_upload) = env::var("OXICLOUD_MAX_UPLOAD_SIZE").map(|v| v.parse::<usize>())
&& let Ok(val) = max_upload
@@ -30,6 +30,8 @@ const SYSTEM_BOOK_ID: &str = "system";
pub struct ContactsApiState {
pub contact_service: Arc<ContactStorageAdapter>,
pub auth_service: Option<Arc<AuthApplicationService>>,
/// When false, the virtual "system" address book (OxiCloud users) is hidden.
pub expose_system_users: bool,
}
/// Address book entry with `is_readonly` and `is_system` flags.
@@ -251,7 +253,7 @@ pub async fn list_address_books(
})
.collect();
if state.auth_service.is_some() {
if state.expose_system_users && state.auth_service.is_some() {
let now = Utc::now();
response.push(AddressBookResponse {
id: SYSTEM_BOOK_ID.to_string(),
@@ -438,6 +440,9 @@ pub async fn list_contacts(
Query(params): Query<ListQuery>,
) -> impl IntoResponse {
if book_id == SYSTEM_BOOK_ID {
if !state.expose_system_users {
return system_book_unavailable();
}
let Some(auth_service) = &state.auth_service else {
return system_book_unavailable();
};
@@ -544,6 +549,9 @@ pub async fn get_contact(
Path((book_id, contact_id)): Path<(String, String)>,
) -> impl IntoResponse {
if book_id == SYSTEM_BOOK_ID {
if !state.expose_system_users {
return system_book_unavailable();
}
let Some(auth_service) = &state.auth_service else {
return system_book_unavailable();
};
+1
View File
@@ -405,6 +405,7 @@ pub fn create_api_routes(app_state: &Arc<AppState>) -> Router<Arc<AppState>> {
let contacts_state = ContactsApiState {
contact_service,
auth_service: auth_svc,
expose_system_users: app_state.core.config.features.expose_system_users,
};
let contacts_router = Router::new()